一、前言

学了真香的vue3语法,但目前的vue2项目中短期内不会再升级了,空有屠龙之术无法施展?来试试以下的解决方案,让你在vue2项目中也能用上vue3的核心语法-组合式API

二、选项式API vs 组合式API

选项式API

vue单文件组件中,一段逻辑(比如更新用户信息)被各种生命周期、methods、data、props等不同的选项分离到不同的部分,维护时需要在不同的选项中找到与这段逻辑相关的代码进行修改,从而造成功能难以维护。这种将一段逻辑分割为不同选项的编写方式就叫选型式API。

组合式API

vue3中,你可将一段逻辑都放在setup模块下,包括数据引用、生命周期中执行操作、watch监听、computed计算、return方法或数据给template使用,这种将一段逻辑组合到一起编写的方式就叫组合式API。

Vue3 composition-api 有哪些劣势?

这是知乎上的一个对于composition-api优劣的讨论,对比了vue2的选项式API和react-hooks两种方案。

简单的说组合式API在设计理念上是最棒的一种,高内聚低耦合。缺点主要是:逻辑都放在setup中,看起来乱了(个人觉得比起之前的结构要清晰不少)。当然,仁者见仁智者见智~

vue2中也能使用组合式API,是真的吗?

这个问题不用去知乎提问了,是真的,接下来就是我们的主角登场。

三、环境配置

1. 安装

首先安装@vue/composition-api,这个是vue2版本支持组合式API的插件

npm install @vue/composition-api
# or
yarn add @vue/composition-api

2. 引入

一般在初始化vue配置的main.js文件中,加入如下配置

import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'

Vue.use(VueCompositionAPI)

四、使用

例子很简单,别被一段代码给吓跑了

接下来的以vue官方文档给出的demo为例,以下是vue2中很常见的一段选项式API代码。

export default {
  components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
  props: {
    user: { 
      type: String,
      required: true
    }
  },
  data () {
    return {
      repositories: [], // 1
      filters: { ... }, // 3
      searchQuery: '' // 2
    }
  },
  computed: {
    filteredRepositories () { ... }, // 3
    repositoriesMatchingSearchQuery () { ... }, // 2
  },
  watch: {
    user: 'getUserRepositories' // 1
  },
  methods: {
    getUserRepositories () {
      // 使用 `this.user` 获取用户仓库
    }, // 1
    updateFilters () { ... }, // 3
  },
  mounted () {
    this.getUserRepositories() // 1
  }
}

注意: 代码备注中的1、2、3,分别代表了用户仓库获取、查询以及筛选检索三种功能对应的逻辑。当组件中逻辑越来越多,可能一段逻辑相关的代码会被分割为更多选项,难以维护。接下来我们尝试用composition-api改造。

1. ref设置数据为响应式

组合式api中data里面的数默认为响应式数据,而组合式api setup 中的数据默认为非响应式,要想转化为响应式,需要使用vue3(或compositin-api)中暴露出的ref,让ref包裹这个变量。

要想在template中使用setup中定义的对象或方法,需要return出来。

import { ref } from '@vue/composition-api'
export default {
-    data () {
-        return {
-          repositories: [], // 1
-        },
-    },
+    setup () {
+        let repositories = ref([])
+        return { repositories }
+    }
}

2. methods处理

setup第一个参数为传入的props,接下来只需要将methods中的函数放入setup并改造为普通函数即可。

import { ref } from '@vue/composition-api'
export default {
-    setup () {
+    setup (props) {
        let repositories = ref([])
+        const getUserRepositories = async () => {
+            repositories = await fetchUserRepositories(props.user)
+        }
-        return { repositories }
+        return { repositories, getUserRepositories }
    },
-    methods: {
-        getUserRepositories () {
-          // 使用 `this.user` 获取用户仓库
-        }
-    }
}

3. 生命周期处理

使用on加上生命周期名称即可在setup中使用生命周期函数。

- import { ref } from '@vue/composition-api'
+ import { ref, onMounted } from '@vue/composition-api'
export default {
    setup (props) {
        let repositories = ref([])
        const getUserRepositories = async () => {
            repositories = await fetchUserRepositories(props.user)
        }
-       mounted () {
-           this.getUserRepositories()
-       }
+       onMounted(getUserRepositories)
        return { repositories, getUserRepositories }
    }
}

4. watch监听处理

  • 需要响应式引用props中的数据,需用到toRefs
  • watch和toRefs同样需要从vue中导出
  • setup中使用某个对象的值时,需要加上对象.value
- import { ref, onMounted } from '@vue/composition-api'
+ import { ref, onMounted, watch, toRefs } from '@vue/composition-api'
export default {
    setup (props) {
+       const { user } = toRefs(props)
        
        let repositories = ref([])
        const getUserRepositories = async () => {
-           repositories = await fetchUserRepositories(props.user)
+           repositories = await fetchUserRepositories(user.value)
        }
        onMounted(getUserRepositories)
+       watch(user, getUserRepositories)
        return { repositories, getUserRepositories }
    }
-   watch: {
-       user: 'getUserRepositories' // 1
-   }
}

用户仓库获取部分改造后的完整代码如下,是不是很简单?

import { ref, onMounted, watch, toRefs } from '@vue/composition-api'
export default {
    setup (props) {
        const { user } = toRefs(props)
        
        let repositories = ref([])
        const getUserRepositories = async () => {
            repositories = await fetchUserRepositories(user.value)
        }
        onMounted(getUserRepositories)
        watch(user, getUserRepositories)
        return { repositories, getUserRepositories }
    }
}

五、Q&A

1. 选项式API与组合式API能否共存?

可以,所以你可以渐进式的重构你的代码。

2. template和setup中数据的引用有什么不同?

  • template中可以直接使用
  • setup中需要加.value

3. 如何使用vue2里this暴露出一些方法(比如 this.$forceUpdate , this.$emit )?

使用setup的第二个参数,示例如下

import { ref } from 'vue'

setup (props, context) {
    context.$emit('update')
}

4. 使用composition-api重构项目后,vue版本升级到3.x怎么办?

直接将@vue/composition-api替换为vue的引入即可。

- import { ref, onMounted, watch, toRefs } from '@vue/composition-api'
+ import { ref, onMounted, watch, toRefs } from 'vue' // vue版本需要3.X

END

Logo

前往低代码交流专区

更多推荐