# Vue.mixin/extend
在项目中, 使用import Vue from 'vue'
来引入vue的构造函数.
而Vue.mixin()
则会不断地修改Vue.options
从而永久性地影响之后实例化的对象
Vue.mixin = function (mixin: Object) {
this.options = mergeOptions(this.options, mixin)
return this
}
2
3
4
我们同样可以利用Vue.extend
创建一个子类, 为它预置一些options, 但是它不会修改Vue.options
, 因此不会影响父类. 你可以构造你的子类, 限制影响范围.
TIP
但是Vue.mixin
会影响到所有Vue.extend
的子类. 即便你是如下的顺序去创建子类, 最后调用的Vue.mixin
也会影响到子类. vue内部有专门的代码判断这种情况 (opens new window)
Vue.mixin(option1)
const Child = Vue.extend(optionChild)
Vue.mixin(option2)
2
3
Vue.mixin
通常只有在你需要全局地影响你项目中所有的Vue实例, 才会用到.
比如一些插件vue-router
, vuex
, vue-router
需要全局性地注入一些生命钩子, 从而保证你所有的组件都能通过this.$router
来访问到router实例, ect.
# 为什么突然注意到Vue.mixin
?
我们使用Vue.ues
来注册插件, 配合Vue.component
可以全局注册组件, Vue.component
实际上是在Vue的构造函数上添加这些组件(vm.constructor.options.components
), 从而使得后续实例化的Vue实例, 全都能从vm.$options
上拿到这些组件(通过将vm.$options
指向vm.constructor.options
)
vue/src/core/instance/init.js
const opts = vm.$options = Object.create(vm.constructor.options)
但是在一次业务开发中, 我发现vm.constructor.options.components
的结构并不是很直观, 原型链有很多冗余
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
Vue.component('globalComponentExample', {
data () {
return {
}
}
})
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
console.log(Vue.options)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
对应的Vue.options
如下
如果代码改成这样
Vue.config.productionTip = false
Vue.mixin({})
Vue.mixin({})
Vue.component('globalComponentExample', {
data () {
return {
}
}
})
2
3
4
5
6
7
8
9
10
11
12
components
的原型链会变成这样
这个问题的根本是涉及了Vue.mixin
的components
的合并策略
Vue.mixin = function (mixin: Object) {
this.options = mergeOptions(this.options, mixin)
return this
}
2
3
4
Vue.mixin
时, 会先针对Vue.options
上已有的属性进行一次合并
mergeOptions
for (key in parent) {
mergeField(key)
}
for (key in child) {
if (!hasOwn(parent, key)) {
mergeField(key)
}
}
2
3
4
5
6
7
8
Vue.options
上默认肯定是有components
属性的, 所以我们使用Vue.mixin
的时候, 肯定会执行一次mergeField('components')
, 而components
的合并策略由下面的代码决定. 所以每调用一次Vue.mixin
, components
的原型链长度就会+1.
对components
的这种合并策略, 持保持态度, 没什么大问题
function mergeAssets (
parentVal: ?Object,
childVal: ?Object,
vm?: Component,
key: string
): Object {
const res = Object.create(parentVal || null)
if (childVal) {
process.env.NODE_ENV !== 'production' && assertObjectType(key, childVal, vm)
return extend(res, childVal)
} else {
return res
}
}
ASSET_TYPES.forEach(function (type) {
strats[type + 's'] = mergeAssets
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
实际上, 很多地方都会有Vue.mixin
的调用, 比如vue router, vuex, vue devtool, 所以有时候Vue.options.components
会呈现一种原型链冗长的状态.