当前位置:   article > 正文

vue2—— mixin 超级详细!!!_vue2 mixin

vue2 mixin

mixin

Mixin面向对象程序设计语言中的类,提供了方法的实现。其他类可以访问mixin类的方法而不必成为其子类

Mixin类通常作为功能模块使用,在需要该功能时“混入”,有利于代码复用又避免了多继承的复杂

vue中的mixin

先来看一下官方定义

mixin(混入),提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。

本质其实就是一个js对象,它可以包含我们组件中任意功能选项,如datacomponentsmethodscreatedcomputed等等

我们只要将共用的功能以对象的方式传入 mixins选项中,当组件使用 mixins对象时所有mixins对象的选项都将被混入该组件本身的选项中来

Vue中我们可以局部混入全局混入

局部混入

首先在 src 同级目录下 创建 mixin/index.js 文件 

  1. export const mixins = {
  2. data() {
  3. return {
  4. msg: "我是mixin中的数据",
  5. };
  6. },
  7. computed: {},
  8. created() {
  9. console.log("我是 mixin 中的 created 生命周期函数");
  10. },
  11. mounted() {},
  12. methods: {
  13. geMes(){
  14. console.log("我是点击事件 hhhhh");
  15. }
  16. },
  17. };

在组件中使用

  1. <script>
  2. import { mixins } from "./mixin/index";
  3. export default {
  4. name: "app",
  5. mixins: [mixins],
  6. created() {
  7. console.log("我是app的生命周期 created",this.msg);
  8. this.geMes()
  9. }
  10. };
  11. </script>

结果

以上代码引入 mixin 的方法很简单,直接使用vue提供给我们的mixins 属性:mixins:[mixins]

总结:

  • mixin 中的生命周期函数会和组件中的生命周期函数一起合并执行
  • mixin 中的data数据在组件中也可以使用
  • mixin 中的方法在组件内部可以直接调用
  • 生命周期函数 合并后 执行顺序:先执行mixin中的,后执行组件的

那么多个组件使用相同的 mixin, 当mixin被修改了 其他组件数据会发生变化吗?

在 components中创建一个 demo 组件

代码如下

  1. // demo.vue
  2. <template>
  3. <div>
  4. <p>我是 demo 组件</p>
  5. <p>我使用了 mixin 中的数据 msg —————— {{ msg }}</p>
  6. </div>
  7. </template>
  8. <script>
  9. import { mixins } from "@/mixin/index";
  10. export default {
  11. name: "app",
  12. mixins: [mixins],
  13. }
  14. </script>

 

 app组件

  1. // app.vue
  2. <template>
  3. <div>
  4. <!-- 组件 -->
  5. <demo/>
  6. <!-- app 本体内容 -->
  7. <div>
  8. 我是app页面的按钮 点击修改mixin中的msg
  9. <p>mixin —————— {{ msg }}</p>
  10. <button @click="setMsg">修改msg</button>
  11. </div>
  12. </div>
  13. </template>
  14. <script>
  15. import demo from './components/demo.vue';
  16. import { mixins } from "./mixin/index";
  17. export default {
  18. components: { demo },
  19. name: "app",
  20. mixins: [mixins],
  21. methods: {
  22. setMsg() {
  23. this.msg = "我被修改了!!!"
  24. }
  25. }
  26. };

结果

结论

在app组件更改了 msg,demo没有变化,所以 不同组件中的mixin 是相互独立的

全局混入

在mian.js 挂载mixin就可以每个组件使用了

  1. import Vue from 'vue'
  2. import App from './App.vue'
  3. import { mixins } from "./mixin/index";
  4. Vue.mixin(mixins)
  5. Vue.config.productionTip = false
  6. new Vue({
  7. render: h => h(App),
  8. }).$mount('#app')

请谨慎使用全局混入,因为它会影响每个单独创建的 Vue 实例 (包括第三方组件)。大多数情况下,只应当应用于自定义选项,就像上面示例一样。推荐将其作为插件发布,以避免重复应用混入。

选项合并

当mixin中定义的属性或方法的名称与组件中定义的名称发生冲突怎么办?

从源码上看 可以分为如下几种类型

  • 替换型
  • 合并型
  • 队列型
  • 叠加型

替换型

替换型合并有propsmethodsinjectcomputed

  1. strats.props =
  2. strats.methods =
  3. strats.inject =
  4. strats.computed = function (
  5. parentVal: ?Object,
  6. childVal: ?Object,
  7. vm?: Component,
  8. key: string
  9. ): ?Object {
  10. if (!parentVal) return childVal // 如果parentVal没有值,直接返回childVal
  11. const ret = Object.create(null) // 创建一个第三方对象 ret
  12. extend(ret, parentVal) // extend方法实际是把parentVal的属性复制到ret中
  13. if (childVal) extend(ret, childVal) // 把childVal的属性复制到ret中
  14. return ret
  15. }
  16. strats.provide = mergeDataOrFn

 同名的propsmethodsinjectcomputed会被后来者代替

 

合并型

和并型合并有:data

  1. strats.data = function(parentVal, childVal, vm) {
  2. return mergeDataOrFn(
  3. parentVal, childVal, vm
  4. )
  5. };
  6. function mergeDataOrFn(parentVal, childVal, vm) {
  7. return function mergedInstanceDataFn() {
  8. var childData = childVal.call(vm, vm) // 执行data挂的函数得到对象
  9. var parentData = parentVal.call(vm, vm)
  10. if (childData) {
  11. return mergeData(childData, parentData) // 将2个对象进行合并
  12. } else {
  13. return parentData // 如果没有childData 直接返回parentData
  14. }
  15. }
  16. }
  17. function mergeData(to, from) {
  18. if (!from) return to
  19. var key, toVal, fromVal;
  20. var keys = Object.keys(from);
  21. for (var i = 0; i < keys.length; i++) {
  22. key = keys[i];
  23. toVal = to[key];
  24. fromVal = from[key];
  25. // 如果不存在这个属性,就重新设置
  26. if (!to.hasOwnProperty(key)) {
  27. set(to, key, fromVal);
  28. }
  29. // 存在相同属性,合并对象
  30. else if (typeof toVal =="object" && typeof fromVal =="object") {
  31. mergeData(toVal, fromVal);
  32. }
  33. }
  34. return to

mergeData函数遍历了要合并的 data 的所有属性,然后根据不同情况进行合并:

  • 当目标 data 对象不包含当前属性时,调用 set 方法进行合并(set方法其实就是一些合并重新赋值的方法)
  • 当目标 data 对象包含当前属性并且当前值为纯对象时,递归合并当前对象值,这样做是为了防止对象存在新增属性

队列型

队列性合并有:全部生命周期和watch

  1. function mergeHook (
  2. parentVal: ?Array<Function>,
  3. childVal: ?Function | ?Array<Function>
  4. ): ?Array<Function> {
  5. return childVal
  6. ? parentVal
  7. ? parentVal.concat(childVal)
  8. : Array.isArray(childVal)
  9. ? childVal
  10. : [childVal]
  11. : parentVal
  12. }
  13. LIFECYCLE_HOOKS.forEach(hook => {
  14. strats[hook] = mergeHook
  15. })
  16. // watch
  17. strats.watch = function (
  18. parentVal,
  19. childVal,
  20. vm,
  21. key
  22. ) {
  23. // work around Firefox's Object.prototype.watch...
  24. if (parentVal === nativeWatch) { parentVal = undefined; }
  25. if (childVal === nativeWatch) { childVal = undefined; }
  26. /* istanbul ignore if */
  27. if (!childVal) { return Object.create(parentVal || null) }
  28. {
  29. assertObjectType(key, childVal, vm);
  30. }
  31. if (!parentVal) { return childVal }
  32. var ret = {};
  33. extend(ret, parentVal);
  34. for (var key$1 in childVal) {
  35. var parent = ret[key$1];
  36. var child = childVal[key$1];
  37. if (parent && !Array.isArray(parent)) {
  38. parent = [parent];
  39. }
  40. ret[key$1] = parent
  41. ? parent.concat(child)
  42. : Array.isArray(child) ? child : [child];
  43. }
  44. return ret
  45. };

生命周期钩子和watch被合并为一个数组,然后正序遍历一次执行

叠加型

叠加型合并有:componentdirectivesfilters

  1. strats.components=
  2. strats.directives=
  3. strats.filters = function mergeAssets(
  4. parentVal, childVal, vm, key
  5. ) {
  6. var res = Object.create(parentVal || null);
  7. if (childVal) {
  8. for (var key in childVal) {
  9. res[key] = childVal[key];
  10. }
  11. }
  12. return res
  13. }

叠加型主要是通过原型链进行层层的叠加

小结:

  • 替换型策略有propsmethodsinjectcomputed,就是将新的同名参数替代旧的参数
  • 合并型策略是data, 通过set方法进行合并和重新赋值
  • 队列型策略有生命周期函数和watch,原理是将函数存入一个数组,然后正序遍历依次执行
  • 叠加型有componentdirectivesfilters,通过原型链进行层层的叠加

mixin的优缺点

从上面的例子看来,使用mixin的好处多多,但是凡是都有两面性,这里总结几点优缺点供大家参考:

 优点

  • 提高代码复用性
  • 无需传递状态
  • 维护方便,只需要修改一个地方即可

缺点

  • 命名冲突
  • 滥用的话后期很难维护
  • 不好追溯源,排查问题稍显麻烦
  • 不能轻易的重复代码

总结

mixin给我们提供了方便的同时也给我们带来了灾难,所以有很多时候不建议滥用它,但是在有些场景下使用它又是非常合适的,这就得根据自己来取舍了。所以在很多时候我们需要考虑用公共组件还是使用mixin。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/873726
推荐阅读
相关标签
  

闽ICP备14008679号