关于Vue2中混入(mixin)的详细介绍

1,334 阅读3分钟

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

一、基本使用

1、定义一个混入(mixin) image.png

2、在组件中使用 image.png

注意观察 Home 组件里面,并没有任何的生命周期钩子或者方法,但是打开页面之后查看控制台,却打印了内容,这就是混入对象中 created 钩子的 console.log() 。 image.png

现在,在Home组件加上mounted生命周期钩子 image.png

查看控制台打印信息: image.png

非但没报错, 还打印出了混入对象中定义的hello方法,也验证了当前组件中合并了混入对象中定义的选项和方法。

二、选项合并

当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。

如下,我们在Home.vue中定义与混入对象中同名的选项

mixin.js image.png

Home.vue image.png

查看控制台打印信息: image.png

此时,同名的created生命周期钩子进行了合并,合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。而 methods 中的 hello 方法因为冲突,在合并时保留组件中的hello,即优先当前组件的选项,因此打印的是 hello from Home!

值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。

三、可复用性

开篇提过,混入对象可成为一个可复用功能,我们在另外的组件中引入已定义的混入对象,可实现同样的逻辑与功能。

如在另外一个组件About.vue使用该混入对象 image.png

查看控制台打印信息: image.png

那么有个问题,如果很多个组件同时使用同一个混入对象,这时候都要重复一个步骤,就是先导入混入对象,然后再使用,类似如下

<script>
    import myMixins from "../mixins";
    export default {
      mixins: [myMixins]
    };
</script>

这样未免有点繁琐,且代码冗余,此时我们可以使用全局混入来优化这个问题。

四、全局混入

混入也可以进行全局注册。使用时格外小心!一旦使用全局混入,它将影响每一个之后创建的 Vue 实例。使用恰当时,这可以用来为自定义选项注入处理逻辑。

在 main.js 中通过 Vue.mixin() 引入混入对象即可全局使用 image.png

效果与在每个组件中单独引入混入对象相同,这便是全局混入。

五、源码分析

export default function initMixin(Vue){
  Vue.mixin = function (mixin) {
    //   合并对象
      this.options=mergeOptions(this.options,mixin)
  };
}
};

// src/util/index.js
// 定义生命周期
export const LIFECYCLE_HOOKS = [
  "beforeCreate",
  "created",
  "beforeMount",
  "mounted",
  "beforeUpdate",
  "updated",
  "beforeDestroy",
  "destroyed",
];

// 合并策略
const strats = {};
// mixin核心方法
export function mergeOptions(parent, child) {
  const options = {};
  // 遍历父亲
  for (let k in parent) {
    mergeFiled(k);
  }
  // 父亲没有 儿子有
  for (let k in child) {
    if (!parent.hasOwnProperty(k)) {
      mergeFiled(k);
    }
  }

  //真正合并字段方法
  function mergeFiled(k) {
    if (strats[k]) {
      options[k] = strats[k](parent[k], child[k]);
    } else {
      // 默认策略
      options[k] = child[k] ? child[k] : parent[k];
    }
  }
  return options;
}