前段时间用 vue3 做了个项目,由于是第一次用 vue3,Composition API 的写法上和过去用过的 vue2 有诸多差异,在逻辑复用这块改善明显,简单和过去的 mixins(官方中文叫“混入”)比较一下。
vue2 mixins
在vue2中,我通常会使用mixin来复用代码,在多个组件里复用相同的逻辑,在组件中使用 mixin 时,mixin 对象中的所有选项都会混合到组件自己对应的选项里。当组件和 mixin 对象含有同名选项时,这些选项会合并。
例子:
// 定义一个mixin对象
var mixin = {
data: function () {
return {
message: 'hello',
foo: 'abc'
}
}
}
// 定义一个使用mixin对象的组件
new Vue({
mixins: [mixin],
data: function () {
return {
message: 'goodbye',
bar: 'def'
}
},
created: function () {
console.log(this.$data)
// => { message: "goodbye", foo: "abc", bar: "def" }
}
})
vue2 的 mixins 有很多让人诟病的地方,mixins 的深度合并非常隐式,这让代码逻辑更难理解和调试,具体表现为如下几点:
- mixins 容易冲突:因为每个特性的属性都被合并到同一个组件中,组件内同名的属性或方法会把 mixins 里的覆盖掉。
- 可重用性有限:不能向 mixins 传递任何参数来改变它的逻辑,这降低了它们在抽象逻辑方面的灵活性。
- 数据来源不清晰:组件里所使用的 mixins 里的数据或方法在当前组件代码里搜索不到,易造成错误的解读,比如被当成错误代码或冗余代码而误删。
vue3 自定义 hooks
vue3 的 Composition Api 中,有点像 react,可以用自定义 hooks 来实现逻辑复用,“以函数形式抽离一些可复用的方法像钩子一样挂着,随时可以引入和调用,实现高内聚低耦合的目标”,总结一下就是:
- 将可复用功能抽离为外部 js 文件
- 函数名/文件名以 use 开头,形如:
useXXX
- 引用时将响应式变量或者方法显式解构暴露出来如:
const {nameRef,Fn} = useXX()
一个计数器的例子:
// useCounter.js
import { ref, computed } from 'vue'
export default function () {
const count = ref(0)
const double = computed(() => count.value * 2)
function increment() {
count.value++
}
return {
count,
double,
increment
}
}
// App.vue
<template>
<p>{{ count }}</p>
<p>{{ double }}</p>
<button @click="increment">increment</button>
</template>
<script>
import useCounter from './useCounter'
export default {
setup() {
const { count, double, increment} = useCounter()
return {
count,
double,
increment
}
},
}
</script>
可以看到,这里没有再使用mixins
属性来引入逻辑代码,本质上只是封装了一个 js 文件引入使用而已,这样使用后,数据来源清晰可见,代码引用有依有据。mixin 中的命名冲突及维护不易的问题也可以被解决。
所以当组件间需要共用逻辑时,建议使用 vue3 中的 Composition API,完全避免了 mixin 方式的种种痛点。
参考资料
https://cn.vuejs.org/v2/guide/mixins.html
https://www.jianshu.com/p/6e519d661b6f