概念
vue官方文档中是这样说的:
混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
混入分为局部混入和全局混入,全局和局部的概念和全局组件、局部组件相同,这里不再赘述。
弊端
当你再项目中使用了过多的mixin,可能会造成项目难于维护的局面,这里说的难以维护指的是,你可能不能快速找到你的变量或者方法等是在何处定义的。
选项合并(需要多加注意)
当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。
比如,数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。
同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。
值为对象的选项,例如 methods
、components
和 directives
,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。
代码示例
1、代码结构
我创建了一个mixin文件夹,里边创建了一个test1.js文件,代表的是一个混入对象,当然也可以创建多个js文件,代表多个混入对象,因为mixins接受的是一个数组。
2、App.vue(其中代码仅用于演示)
在app.vue中我使用了keep-alive包裹了router-view,这是为了演示混入和vuex的区别
vuex是全局状态管理,在修改state中的值时,所有依赖的组件都会重新render,而混入每个组件都是独立的数据,不会互相影响
<template>
<div id="app">
<img src="./assets/logo.png" />
<button @click="goPage1">testPage1</button>
<button @click="goPage2">testPage2</button>
<button @click="goPage3">testPage3</button>
<keep-alive>
<router-view />
</keep-alive>
</div>
</template>
<script>
export default {
name: 'App',
methods: {
goPage1 () {
this.$router.push('/testPage1')
},
goPage2 () {
this.$router.push('/testPage2')
},
goPage3 () {
this.$router.push('/testPage3')
}
}
}
</script>
3、test1.js
混入对象和vue组件中的各个生命周期、数据等的定义是一致的
export const test1 = {
data () {
return {
count: 1
}
},
created () {
console.log('我是mixin混入对象')
}
}
4、pageOne.vue
在这个页面中,我们提供了一个修改count的方法,此方法改变数据不会影响到其他使用此混入对象的页面。
这里能读取到this.count是如上文所说:
当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
如下图所示:我们改变了页面1中混入对象的count值,但页面2中的值并没有受到影响。
<template>
<div>
<h1>我是页面1</h1>
<h2>count:{{ count }}</h2>
<button @click="addCount">增加count</button>
</div>
</template>
<script>
import { test1 } from '@/mixin/test1.js'
export default {
mixins: [test1],
methods: {
addCount () {
this.count++
}
}
}
</script>
<style></style>
5、pageTwo.vue
在这个页面中,会执行两个console,先执行的是混入对象中created中的console.log('我是mixin混入对象'),后执行当前组件的created方法中的console.log('我是页面2')
这也就是上文说的:
同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。
如下图所示:当我们点击testPage2时,先打印的“我是mixin混入对象”,后打印了“我是页面2”
<template>
<div>
<h1>我是页面2</h1>
<h2>count:{{ count }}</h2>
</div>
</template>
<script>
import { test1 } from '@/mixin/test1.js'
export default {
mixins: [test1],
created () {
console.log('我是页面2')
}
}
</script>
<style></style>
6、pageThree.vue
此页面组件中也定义了一个和混入对象同名的count变量,页面中展示的数据为3,并不是混入对象中的1,这也是上文所说:
数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。
如下图:我们可以看到,页面1和页面2的值都为1,而页面3的值为3
<template>
<div>
<h1>我是页面3</h1>
<h2>count:{{ count }}</h2>
</div>
</template>
<script>
import { test1 } from '@/mixin/test1.js'
export default {
mixins: [test1],
data () {
return {
count: 3
}
}
}
</script>
<style></style>
全局混入
请谨慎使用全局混入,因为它会影响每个单独创建的 Vue 实例 (包括第三方组件)。
自定义选项合并策略
自定义选项将使用默认策略,即简单地覆盖已有值。如果想让自定义选项以自定义逻辑合并,可以向 Vue.config.optionMergeStrategies
添加一个函数:
Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) {
// 返回合并后的值
}