前言
混入(mixin)的使用非常简单,其实我原本打算直接写插件(plugin)的,但考虑到插件的使用范围也包括混入和自定义指令,还是先讲讲这两个的基本概念。
混入在我看来,就是给组件加上一些通用的属性和方法。比如说我们项目有很多个页面是要展示分页列表的,那页面组件都会包含当前页、每页记录、总记录数、总页数这些属性、还有页面增删查改操作的函数等等,其中有很多是完全一样,或者具备一定可复用性的。如果每个页面都搞这么一大坨,不单写起来繁琐,看起来也很乱。要是碰上不同的人开发,变量名定义还不一样,可读性可维护性就很差。所以我们想要有个东西能把这些共同的部分提取出来,这里面就要用到混入的概念。项目中如何使用大家可以参考一些开源的后台管理系统,比如jeecg的前端就用了混入。
使用混入
先利用vue-cli建一个项目test_mixin。不懂建的参考我第一篇vue文章《Vue学习(一)——组件基础》。
基本使用
现在我们假设我们项目的每个组件created方法都调用console.log('create'),并且每个组件都有一个hello方法,另外还有两个属性current、pageSize。
创建目录src/mixin,并在该目录下新建文件mixinHello.js:
export const mixinHello = {
data(){
return{
current: 1,
pageSize: 10
}
},
created: function () {
console.log('create')
},
methods: {
hello: function () {
console.log('hello from mixin!')
console.log('current:' + this.current)
console.log('pageSize:' + this.pageSize)
}
}
}
代码很简单,就是像我们这节开始说的那样,定义好current、pageSize属性,created方法、hello方法。接着我们在src/components目录下创建一个自定义按钮组件myBtn,并把混入加到其中:
<template>
<div>
<button @click="hello">测试混入</button>
</div>
</template>
<script>
import {mixinHello} from '@/mixin/mixinHello.js'
export default {
mixins: [mixinHello]
}
</script>
然后我们修改App.vue,引入muBtn
<template>
<div>
<my-btn></my-btn>
</div>
</template>
<script>
import myBtn from '@/components/myBtn'
export default {
name: 'App',
components: {
myBtn
},
}
</script>
执行run server,访问localhost:8080,如图:
我们点F12打开开发者工具,刷新页面,可以看到打印出create,证明调用了mixinHello的created方法:
然后点击按钮,打印出hello方法执行的内容。
当然如果这些方法和属性仅仅用在一个组件上,显然是没必要使用混入。混入的意义在于复用,如果很多组件都需要用到这些方法和属性,使用混入就恰到好处了。
选项合并
混入在复用时可以节省很多功夫,但是有衍生出另一个问题,如果我们在组件里面定义了名称相同的方法或者属性,执行的时候会用哪个?我们在src/components目录下创建零一个自定义按钮组件myBtnMerge.vue
<template>
<div>
<button style="margin: 10px" @click="hello">测试混入合并</button>
</div>
</template>
<script>
import {mixinHello} from '@/mixin/mixinHello.js'
export default {
mixins: [mixinHello],
data(){
return{
current: 2,
pageSize: 30
}
},
created: function () {
console.log('create merge')
},
methods: {
hello: function () {
console.log('hello merge!')
console.log('current:' + this.current)
console.log('pageSize:' + this.pageSize)
}
}
}
</script>
修改App.vue,注释掉myBtn,加上myBtnMerge
<template>
<div>
<!-- <my-btn></my-btn> -->
<my-btn-merge></my-btn-merge>
</div>
</template>
<script>
// import myBtn from '@/components/myBtn'
import myBtnMerge from '@/components/myBtnMerge'
export default {
name: 'App',
components: {
// myBtn,
myBtnMerge
},
}
</script>
运行项目后,刷新网页,然后点击按钮,看到F12的输出:
这里我们有三个结论:
1、对于钩子函数,比如created、mounted、destroyed一类,组件自定义的方法和混入的方法同名时,会合并,并且混入的方法先于组件自定义的调用。
2、对于组件自定义的数据对象,和混入对象合并后,如果存在冲突的属性,则以组件自定义的优先。
3、对于methods、components 和 directives这一类,组件自定义的与混入的内部键值存在冲突时,以组件自定义的优先。
看起来这个有点像面向对象的继承。钩子函数像构造函数。其他则类似成员属性和成员方法。
如果不想使用默认的合并策略,混入还可以自定义合并的策略。具体实现读者可以自行搜索“optionMergeStrategies”这个关键词。
小结
混入的使用在我看来有点像面向对象里面的继承。好处是相同的属性和方法没必要重复写很多遍。尤其是做项目时,每个分页都要写一堆方法非常繁琐。当然对于钩子函数还是要谨慎使用混入,因为即使组件自定义了钩子函数,也不会覆盖混入的钩子函数。