共计 4299 个字符,预计需要花费 11 分钟才能阅读完成。
mixin
Mixin
是面向对象程序设计语言中的类,提供了方法的实现。其他类可以访问mixin
类的方法而不必成为其子类
Mixin
类通常作为功能模块使用,在需要该功能时“混入”,有利于代码复用又避免了多继承的复杂
vue 中的 mixin
先来看一下官方定义
mixin
(混入),提供了一种非常灵活的方式,来分发Vue
组件中的可复用功能。
本质其实就是一个 js
对象,它可以包含我们组件中任意功能选项,如 data
、components
、methods
、created
、computed
等等
我们只要将共用的功能以对象的方式传入 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");
}
},
};
在组件中使用
结果
以上代码引入 mixin 的方法很简单,直接使用 vue 提供给我们的 mixins 属性:mixins:[mixins]
总结:
- mixin 中的生命周期函数会和组件中的生命周期函数一起合并执行
- mixin 中的 data 数据在组件中也可以使用
- mixin 中的方法在组件内部可以直接调用
- 生命周期函数 合并后 执行顺序:先执行 mixin 中的,后执行组件的
那么多个组件使用相同的 mixin,当 mixin 被修改了 其他组件数据会发生变化吗?
在 components 中创建一个 demo 组件
代码如下
// demo.vue
我是 demo 组件
我使用了 mixin 中的数据 msg —————— {{msg}}
app 组件
// app.vue
我是 app 页面的按钮 点击修改 mixin 中的 msg
mixin —————— {{msg}}
结果
结论
在 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 中定义的属性或方法的名称与组件中定义的名称发生冲突怎么办?
从源码上看 可以分为如下几种类型
- 替换型
- 合并型
- 队列型
- 叠加型
替换型
替换型合并有props
、methods
、inject
、computed
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
同名的
props
、methods
、inject
、computed
会被后来者代替
合并型
和并型合并有: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
被合并为一个数组,然后正序遍历一次执行
叠加型
叠加型合并有:component
、directives
、filters
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
}
叠加型主要是通过原型链进行层层的叠加
小结:
- 替换型策略有
props
、methods
、inject
、computed
,就是将新的同名参数替代旧的参数 - 合并型策略是
data
, 通过set
方法进行合并和重新赋值 - 队列型策略有生命周期函数和
watch
,原理是将函数存入一个数组,然后正序遍历依次执行 - 叠加型有
component
、directives
、filters
,通过原型链进行层层的叠加
mixin 的优缺点
从上面的例子看来,使用 mixin 的好处多多,但是凡是都有两面性,这里总结几点优缺点供大家参考:
优点
- 提高代码复用性
- 无需传递状态
- 维护方便,只需要修改一个地方即可
缺点
- 命名冲突
- 滥用的话后期很难维护
- 不好追溯源,排查问题稍显麻烦
- 不能轻易的重复代码
总结
mixin 给我们提供了方便的同时也给我们带来了灾难,所以有很多时候不建议滥用它,但是在有些场景下使用它又是非常合适的,这就得根据自己来取舍了。所以在很多时候我们需要考虑用公共组件还是使用 mixin。
原文地址: vue2—— mixin 超级详细!!!