Appearance
mixin
javascript
// 全局混入, 影响之后创建的每个Vue实例
Vue.mixin({
beforeCreate: function () {
console.log('beforeCreate')
}
})
Vue.mixin({
beforeCreate: [
function () {},
function () {}
]
})javascript
// Vue.mixin 中将 mixin 的配置项和全局配置项 Vue.options 进行合并
Vue.mixin = function (mixin) {
// 合并配置项
this.options = mergeOptions(this.options, mixin)
return this
}javascript
// mergeOptions 用于合并父子配置项,内部定义一个对象 options 用于保存合并结果并最终
// 返回,先遍历 parent,对每个属性调用 mergeField 方法,再遍历 child,对 parent
// 中没有的属性调用 mergeField 方法。
// mergeField 中根据不同的属性选择不同的合并策略,默认的合并策略是只有 childVal
// 为 undefined 时以 parentVal 为准,否则都让 childVal 覆盖 parentVal。
function mergeOptions (parent, child) {
const options = {}
let key
for (key in parent) {
mergeField(key)
}
for (key in child) {
if (!hasOwn(parent, key)) { // 父子中相同的key合并过了
mergeField(key)
}
}
function mergeField (key) {
let strat = strats[key] || defaultStrat // 选择合并策略
options[key] = strat(parent[key], child[key])
}
return options
}
Vue.prototype._init = function (options) {
// 合并全局options和组件options
vm.$options = mergeOptions(vm.constructor.options, options || {})
}
// 钩子合并策略
const LIFECYCLE_HOOKS = [
'beforeCreate',
'created',
'beforeMount',
'mounted',
'beforeUpdate',
'updated',
'beforeDestroy',
'destroyed',
'activated',
'deactivated',
'errorCaptured',
'serverPrefetch'
];
const strats = {}
// 默认合并策略 以childVal为准
const defaultStrat = function (parentVal, childVal) {
return childVal === undefined
? parentVal
: childVal
}
// 钩子合并策略
LIFECYCLE_HOOKS.forEach(hook => {
strats[hook] = mergeHook
})
function mergeHook (parentVal, childVal) {
const res = childVal
? parentVal
// 合并Vue.options[hook] 和 vm.$options[hook],确保mixin 混入的先执行,
? parentVal.concat(childVal)
: Array.isArray(childVal)
? childVal
: [childVal] // 包装成数组
: parentVal // vm.$options[hook] 可能为 undefined
return res
}
// 在合适的位置调用即可
function callHook (vm, hook) {
const handlers = vm.$options[hook]
if (handlers) {
for (let i = 0, l = handlers.length; i < l; i++) {
handlers[i].call(vm)
}
}
}