# mixin

# 简述

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

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

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

var component = new Component() // => "hello from mixin!"

在业务代码中使用 mixin 需要慎重,尤其是全局混入。因为 mixin 会导致数据来源不明确,并且在声明时可能会导致命名冲突,当命名冲突时,会以组件内部的数据优先。

# 原理

mixin 的实现原理非常简单,其实就是在初始化 Vue 实例时,将 mixin 传入的 options 选项和 Vue 的 options 选项合并即可。

    Vue.mixin = function (mixin) {
      // 合并原有的钩子和传进来的钩子
      this.options = mergeOptions(this.options, mixin);
      return this;
    };

mergeOptions:

  // 合并两个对象,合并mixin时用到
  function mergeOptions(parent, child) {
    var options = {};

    // 合并老的属性,其实就是将{create:fn()} => {create:[fn]},数组化
    for (var key in parent) {
      mergeField(key);
    }
    for (var _key in child) {
      if (!parent.hasOwnProperty(_key)) {
        // 不合并已经合并过的属性
        mergeField(_key);
      }
    }

    // 合并options,优先后传入的mixin
    function mergeField(key) {
      if (strats[key]) {
        // 有相应的策略,按照策略合并
        options[key] = strats[key](parent[key], child[key]);
      } else {
        // 策略模式,针对不同的属性采取不同的合并策略
        options[key] = child[key] || parent[key];
      }
    }
    return options;
  }