就在2020年9月的时候,尤大大发布了Vue3的正式版。在这个新版与旧版之间,我觉得变化最大的是多了一个Composition API
。
当你在开发一个大型项目的时候,遇到创建Vue组件时,一个组件跟项目中另外一个组件中存在着大量的重复代码,一旦维护起来所花费成本就大了,最后在维护代码这条路上越走越远。而这里,你或许会想到用 mixins
这个API,虽然这API本身就是为了减少代码的重复性,提交开发效率,但是维护上并没有多大发挥到他的作用,一旦我在共用代码部分修改某项的时候,我这一改的话,会影响到另外一个组件的交互,而这样就不得不跑去另外一个组件修改代码了,我不喜欢这样的操作。
Composition API
就是为了提高共用代码的维护效率而诞生的,此API里面就是用在setup
这个位置上。setup
选项应该是接受props
和context
的函数,我们可以将其返回的所有内容都将暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板。这里有点要注意的是,由于在执行 setup
时尚未创建组件实例,因此在 setup
选项中没有 this
。这意味着,除了 props
之外,你将无法访问组件中声明的任何属性——本地状态、计算属性或方法。
下面为了起到更好对比效果,我分别用 vue2
和 vue3
来实现同样的效果,已达到对比性。
演示效果
Vue3
主页面
<template>
<submit @submit="changeTarget"></submit>
<say v-model:say="change"></say>
<display :say="change" :target="start"></display>
</template>
一开始我设置了三个组件,他们分别是:
- submit 用于提交自己的开始值
- say 用于输入你的内容
- display 用于展示你的效果
say组件
在组件say
我用了vue3中的 v-model
进行双向绑定,在3.x中,自定义组件上的我可以直接更改v-model
的名称,而不是更改组件内的model
选项,这样也就意味我们可以在自定义组件上使用多个 v-model
。
// app.vue
<template>
<say v-model:say="change"></say>
</template>
say
组件内部
// say.vue
<template>
<div class="say">请输入你的内容</div>
<input @input="changeValue" :value="say"/>
</template>
<script type="text/ecmascript-6">
export default {
name: "hello",
props: ["say"],
methods: {
changeValue(e) {
let says = e.target.value;
this.$emit("update:say", says);
},
}
};
</script>
display组件
现在开始主要说下display部分,这一部分我用了Vue3中的Composition API
,而我把setup
部分写在 display
组件那里
// display.vue
<template>
<p>内容展示</p>
<div>乘法:{{muliplyTotal}}</div>
<div>加法:{{addTotal}}</div>
</template>
<script>
import { toRef } from 'vue'
import {muliplyNum, addNum} from "../common/util/tool";
export default {
props: ['target', 'say'],
setup(props) {
let muliplyTotal= muliplyNum(toRef(props, 'target'), toRef(props, 'say'))
let addTotal = addNum(toRef(props, 'target'), toRef(props, 'say'))
return {
muliplyTotal,
addTotal
}
}
}
</script>
props
传递的值,通过 toRef
为源响应对象的property性创建一个 ref
,保持对其源 property的响应式链接,并传递给 muliplyNum
和 addNum
函数,最后将函数返回的结果返回组件上。
// tool.js
import {watch, ref} from 'vue'
export function addNum(start, value) {
let display = ref(0)
watch(value, (newVal) => {
let total = start.value
let arr = newVal.split('')
arr.forEach((i) => {
total = total + parseInt(i)
})
display.value = total
})
return display
}
export function muliplyNum(start, value) {
let display = ref(0)
watch(value, (newVal) => {
let eachValue = start.value
let value = parseInt(newVal)
display.value = parseInt(eachValue) * value
})
return display
}
通过 ref
来为对象 display
创建一个响应式, watch
来观察 props
传递过来的值变化并作出相应的逻辑,逻辑的最后将响应式的数据返回出去。
Vue2
我用了vue2写了一个相同业务逻辑
主页面
在主页面部门大部分相同,只是在组件 say
部分,由于 v-model
双向绑定的要求,要在属性 say
处增加一个 .sync
修饰符来达到双向绑定。
<template>
<div>
<submit @submit="changeTarget"></submit>
<say :say.sync="change"></say>
<display :say="change" :target="start"></display>
</div>
</template>
display组件
<template>
<div>
<p>内容展示</p>
<div>乘法:{{muliplyTotal}}</div>
<div>加法:{{addTotal}}</div>
</div>
</template>
<script type="text/ecmascript-6">
import { addNum, muliplyNum } from '../common/js/tool'
export default {
props: ['say', 'target'],
data () {
return {
muliplyTotal: 0,
addTotal: 0
}
},
watch: {
say (newVal) {
this.addTotal = addNum(this.target, newVal)
this.muliplyTotal = muliplyNum(this.target, newVal)
}
}
}
</script>
与之前的vue3中的 display
组件不同的地方,主要多了一个watch
api来监控从外面传入进来的 say
数,因变化来做出相应的代码逻辑,
// tool.js
export function addNum (start, value) {
let total = start
let arr = value.split('')
arr.forEach((i) => {
total = total + parseInt(i)
})
return total
}
export function muliplyNum (start, value) {
return parseInt(value) * start
}
总结
看到这里或许你会说,干嘛不直接用computed
来进行实现了呢。确实是可以这样操作,代码量确实比现在还要少,更为简单处理。这里我只是为了演示操作,才这样写的。
经过vue3与vue2这两者的代码比较,发现优缺点如下:
- vue2代码虽少,维护起来不友好,某些响应式特性不能单独跟函数封装在一起,造成需要另外在主页面单独设置;
- vue3虽然代码多了,但是组件间通用性高了,因为我把
watch
和ref
等各类响应式api封装在函数里面,如果下次想在别的组件,直接调用该函数即可;
由起看来,Vue3的Composition API
确实能在维护组件方面增强了不少,更多的使用场景需要我们不断去探索,也希望Vue3越来越好。