vue2—— mixin 超级详细!!!

15,588次阅读
没有评论

共计 4299 个字符,预计需要花费 11 分钟才能阅读完成。

mixin

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

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

vue 中的 mixin

先来看一下官方定义

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

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

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

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

局部混入

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

export const mixins = {data() {
    return {msg: "我是 mixin 中的数据",};
  },
  computed: {},
  created() {console.log("我是 mixin 中的 created 生命周期函数");
  },
  mounted() {},
  methods: {geMes(){console.log("我是点击事件 hhhhh");
    }
  },
};

在组件中使用

结果

vue2—— mixin 超级详细!!!

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

总结:

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

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

在 components 中创建一个 demo 组件

代码如下

// demo.vue


 

 app 组件

// app.vue


结果

vue2—— mixin 超级详细!!!

结论

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

全局混入

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

import Vue from 'vue'
import App from './App.vue'
import {mixins} from "./mixin/index";
Vue.mixin(mixins)

Vue.config.productionTip = false

new Vue({render: h => h(App),
}).$mount('#app')

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

选项合并

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

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

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

替换型

替换型合并有propsmethodsinjectcomputed

strats.props =
strats.methods =
strats.inject =
strats.computed = function (
  parentVal: ?Object,
  childVal: ?Object,
  vm?: Component,
  key: string
): ?Object {if (!parentVal) return childVal // 如果 parentVal 没有值,直接返回 childVal
  const ret = Object.create(null) // 创建一个第三方对象 ret
  extend(ret, parentVal) // extend 方法实际是把 parentVal 的属性复制到 ret 中
  if (childVal) extend(ret, childVal) // 把 childVal 的属性复制到 ret 中
  return ret
}
strats.provide = mergeDataOrFn

 同名的 propsmethodsinjectcomputed 会被后来者代替

 

合并型

和并型合并有:data

strats.data = function(parentVal, childVal, vm) {    
    return mergeDataOrFn(parentVal, childVal, vm)
};

function mergeDataOrFn(parentVal, childVal, vm) {return function mergedInstanceDataFn() {var childData = childVal.call(vm, vm) // 执行 data 挂的函数得到对象
        var parentData = parentVal.call(vm, vm)        
        if (childData) {return mergeData(childData, parentData) // 将 2 个对象进行合并                                 
        } else {return parentData // 如果没有 childData 直接返回 parentData}
    }
}

function mergeData(to, from) {if (!from) return to    
    var key, toVal, fromVal;    
    var keys = Object.keys(from);   
    for (var i = 0; i 

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

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

队列型

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

function mergeHook (parentVal: ?Array,
  childVal: ?Function | ?Array
): ?Array {
  return childVal
    ? parentVal
      ? parentVal.concat(childVal)
      : Array.isArray(childVal)
        ? childVal
        : [childVal]
    : parentVal
}

LIFECYCLE_HOOKS.forEach(hook => {strats[hook] = mergeHook
})

// watch
strats.watch = function (
  parentVal,
  childVal,
  vm,
  key
) {
  // work around Firefox's Object.prototype.watch...
  if (parentVal === nativeWatch) {parentVal = undefined;}
  if (childVal === nativeWatch) {childVal = undefined;}
  /* istanbul ignore if */
  if (!childVal) {return Object.create(parentVal || null) }
  {assertObjectType(key, childVal, vm);
  }
  if (!parentVal) {return childVal}
  var ret = {};
  extend(ret, parentVal);
  for (var key$1 in childVal) {var parent = ret[key$1];
    var child = childVal[key$1];
    if (parent && !Array.isArray(parent)) {parent = [parent];
    }
    ret[key$1] = parent
      ? parent.concat(child)
      : Array.isArray(child) ? child : [child];
  }
  return ret
};

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

叠加型

叠加型合并有:componentdirectivesfilters

strats.components=
strats.directives=

strats.filters = function mergeAssets(parentVal, childVal, vm, key) {var res = Object.create(parentVal || null);    
    if (childVal) {for (var key in childVal) {res[key] = childVal[key];
        }   
    } 
    return res
}

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

小结:

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

mixin 的优缺点

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

 优点

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

缺点

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

总结

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

原文地址: vue2—— mixin 超级详细!!!

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于2024-10-23发表,共计4299字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)