Vue2-Vue.mixin 与 mixins

123 阅读2分钟

混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

1# 全局混入:Vue.mixin( mixin )

语法Vue.mixin( options: { Object } )

Vue.mixin({
  created: function () {
    var myOption = this.$options.myOption;
    if (myOption) {
      console.log(myOption);
    }
  },
});

new Vue({
  myOption: "hello, Vue!",
}).$mount("#app");
// 输出: hello, Vue!

2# 局部混入:mixins

语法mixins: [ m1, m2 ]

// 定义一个混入对象
var myMixin = {
  created: function () {
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello, mixin!')
    }
  }
}

// 定义一个使用混入对象的组件
var Component = Vue.extend({
  mixins: [myMixin]
})

var component = new Component()
// 输出: hello, mixin

3# 示例一:选项合并

当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。

(1)混入数据对象

数据对象在内部会进行递归合并, 且同名时以组件数据优先

// 情况1:混入数据对象
var dataMixin = {
  data: function () {
    return {
      p1: "Hello",
      p2: "abc",
    };
  },
};
var vm = new Vue({
  mixins: [dataMixin],
  data: function () {
    return {
      p2: "xyz",
    };
  },
});

console.log(vm.$options.data());
// 输出 { "p2": "xyz", "p1": "Hello" }

(2)混入钩子函数

同名钩子函数将合并为一个数组, 且都会被调用。另外,混入的钩子函数将在组件自身钩子之前调用。

// 情况2:混入钩子函数
var hookMixin = {
  created: function () {
    console.log("Mixin hook: created");
  },
};
var vm = new Vue({
  mixins: [hookMixin],
  created: function () {
    console.log("Component hook: created");
  },
});

console.log(vm.$options.created.length); // 2

/* 输出
Mixin hook: created
Component hook: created
2
*/

(3)混入对象值选项

值为对象的选项将会被合并为同一个对象,且同名时以组件对象优先。 如 methodscomponentsfiltersdirectives 等选项。

// 情况3:混入对象值选项
var optionsMixin = {
  methods: {
    f1: function () {
      console.log('Mixin method: f1');
    },
    f2: function () {
      console.log('Mixin method: f2');
    }
  }
};

var vm = new Vue({
  mixins: [optionsMixin],
  methods: {
    f2: function () {
      console.log('Component method: f2');
    }
  }
});

vm.f1(); // Mixin method: f1
vm.f2(); // Component method: f2

(4)混入自定义选项

// 情况4:混入自定义选项
var optionsMixin = {
    myOption: "Mixin options: myOption",
};

var vm = new Vue({
    mixins: [optionsMixin],
    myOption: "Component options: myOption",
});

console.log(vm.$options.myOption);
// 输出:Component options: myOption

3# 示例二:自定义选项合并

// Vue.config.optionMergeStrategies

activated: ƒ mergeHook( parentVal, childVal )
beforeCreate: ƒ mergeHook( parentVal, childVal )
beforeDestroy: ƒ mergeHook( parentVal, childVal )
beforeMount: ƒ mergeHook( parentVal, childVal )
beforeUpdate: ƒ mergeHook( parentVal, childVal )
components: ƒ mergeAssets( parentVal, childVal, vm, key )
computed: ƒ ( parentVal, childVal, vm, key )
created: ƒ mergeHook( parentVal, childVal )
data: ƒ ( parentVal, childVal, vm )
deactivated: ƒ mergeHook( parentVal, childVal )
destroyed: ƒ mergeHook( parentVal, childVal )
directives: ƒ mergeAssets( parentVal, childVal, vm, key )
el: ƒ (parent, child, vm, key)
errorCaptured: ƒ mergeHook( parentVal, childVal )
filters: ƒ mergeAssets( parentVal, childVal, vm, key )
inject: ƒ ( parentVal, childVal, vm, key )
methods: ƒ ( parentVal, childVal, vm, key )
mounted: ƒ mergeHook( parentVal, childVal )
props: ƒ ( parentVal, childVal, vm, key )
propsData: ƒ (parent, child, vm, key)
provide: ƒ mergeDataOrFn( parentVal, childVal, vm )
serverPrefetch: ƒ mergeHook( parentVal, childVal )
updated: ƒ mergeHook( parentVal, childVal )
watch: ƒ ( parentVal, childVal, vm, key )

(1)自定义选项合并策略

对于自定义选项,如果想让自定义选项以自定义逻辑合并,可以向 Vue.config.optionMergeStrategies 添加一个函数:

Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) {
  console.log("toVal=" + toVal); // 待合并的值
  console.log("fromVal=" + fromVal); // 待合并的值
  return "Merged options:xx"; // 返回合并后的最终结果
};

完整示例如下:

// 混入自定义选项
var myOptionMixin = {
  myOption: "Mixin options: myOption",
};

// 加入合并策略
Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) {
  console.log("toVal=" + JSON.stringify(toVal));
  console.log("fromVal=" + JSON.stringify(fromVal));
  return [].concat(toVal, fromVal); // 返回合并后的值
};

var vm = new Vue({
  mixins: [myOptionMixin],
  myOption: "Component options: myOption",
});

console.log(vm.$options.myOption);
// 默认策略输出:Component options: myOption

/* 加入策略后
toVal=undefined
fromVal="Mixin options: myOption"

toVal=[null,"Mixin options: myOption"]
fromVal="Component options: myOption"

[undefined, 'Mixin options: myOption', 'Component options: myOption']
*/

(2)对象值选项的合并策略

对于值为对象的选项,可以使用与 methodscreated 相同的合并策略:

var strategies = Vue.config.optionMergeStrategies;
strategies.myOption = strategies.methods; // methods 合并策略
strategies.myOption = strategies.created; // created 合并策略

完整示例如下:

// 混入自定义选项
var myOptionMixin = {
  myOption: { v: "Mixin options: myOption" },
};

// 加入合并策略
var strategies = Vue.config.optionMergeStrategies;
strategies.myOption = strategies.methods; // methods 合并策略
// strategies.myOption = strategies.created; // created 合并策略

var vm = new Vue({
  mixins: [myOptionMixin],
  myOption: { v: "Component options: myOption" },
});

console.log(vm.$options.myOption);
// 默认策略输出:{v: 'Component options: myOption'}

/* 加入 methods 合并策略后输出:{v: 'Component options: myOption'} */

/* 加入 created 合并策略后输出:
[{"v": "Mixin options: myOption"}, {"v": "Component options: myOption"}]
*/