我们在用Vue进行前端开发的时候,往往会遇到有很多个组件内,他们都有类似的data,类似的方法。这些大量重复的代码,如果正常编写出来,代码既不美观也不优雅,而且看起来也相当复杂。所以vue官方提供了一个极其好用的方式来解决这个问题
那就是mixin
先来看看官方的介绍
混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
在Java开发中 如果我们遇到两个类有大量相似代码的时候,我们通常会定义一个父类,来讲这些重复代码写在一起,然后再让这两个类来继承父类的代码和方法。
class Animal{ run(){} } class Person extends Animal{ //run(){} } class Dog extends Animal{ //run(){} }
而在Vue中,每个组件export出来的是对象,所以不能像类那样继承,于是Vue提供了类似于类的继承的方法 mixin
使用方法,在这里贴上自己项目的部分代码。
定义一个mixin.js 文件
import {debounce} from './utils'; export const itemListenerMixin = { data(){ return { itemImgListener: null, } }, methods:{ }, mounted(){ let newRefresh = debounce(this.$refs.scroll.refresh, 100) this.itemImgListener = () => { newRefresh() } this.$bus.$on('itemImgLoad', this.itemImgListener) console.log("我是混入的东西") } }
mixin 里就跟一个正常的Vue的组件没有任何的区别,可以定义data,methods,生命周期函数等等。跟Java里面的父类和子类完全一样。只是调用的方法不一样而已。
两个调用mixin.js的组件
Detail.vue
import {itemListenerMixin} from "common/mixin"; mixins: [itemListenerMixin], //其余代码均省略
Home.vue
import {itemListenerMixin} from "common/mixin"; mixins: [itemListenerMixin], //其余代码均省略
只需要这样一小段代码,就可以调用到mixin.js 内定义的组件了。
而且在两个组件内,作用完全一样
当我们在组件上应用Mixin的时候,有可能组件与Mixin中都定义了相同的生命周期钩子,这时候钩子的执行顺序的问题凸显了出来。默认Mixin上会首先被注册,组件上的接着注册,这样我们就可以在组件中按需要重写Mixin中的语句。组件拥有最终发言权。当发生冲突并且这个组件就不得不“决定”哪个胜出的时候,这一点就显得特别重要,否则,所有的东西都被放在一个数组当中执行,Mixin将要被先推入数组,其次才是组件。
const myMixin = { mounted() { console.log('mixin!') } } new Vue({ el: '#app', mixins: [myMixin], mounted() { console.log('Vue instance!') } }); //Output in console > mixin! > Vue instance!
//mixin const myMixin = { methods: { sayHello: function() { console.log('mixin!') } }, mounted() { this.sayHello() } } //vue instance or component new Vue({ el: '#app', mixins: [myMixin], methods: { sayHello: function() { console.log('Vue instance!') } }, mounted() { this.sayHello() } }) // Output in console > Vue instance! > Vue instance!
我们可以看到,当他们之间没有发生同名冲突的时候,两个都正常打印了。而当他们发生冲突之后。你可以看到这里打印了两个Vue instance。这是因为第一个函数被调用之后,并没有被销毁,而是被重写了。然后被调用了两次
当组件和混入对象含有同名选项时,这些选项将以恰当的方式混合。
选项合并
-
数据对象(data)在内部会进行递归合并,在和组件的数据发生冲突时以组件数据优先。
-
同名钩子函数(created,mounted...)将混合为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。
-
值为对象的选项(methods, components 和 directives)将被混合为同一个对象。两个对象键名冲突时,取组件对象的键值对。
需要注意的是
谨慎使用全局混入对象,因为会影响到每个单独创建的 Vue 实例 (包括第三方模板)。大多数情况下,只应当应用于自定义选项。也可以将其用作 Plugins 以避免产生重复应用
所以Vue对mixin 设定了 自定义选项合并策略
自定义选项将使用默认策略,即简单地覆盖已有值。如果想让自定义选项以自定义逻辑合并,可以向
Vue.config.optionMergeStrategies
添加一个函数:
Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) { // 返回合并后的值 }
对于多数值为对象的选项,可以使用与 methods
相同的合并策略:
var strategies = Vue.config.optionMergeStrategies strategies.myOption = strategies.methods
有时间的,可以看看这篇文件对mixin源码的观察