当组件和混入对象含有同名选项时,Vue 会按照特定规则进行合并。理解这些规则对于正确使用混入至关重要。
数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先:
const mixin = {
data() {
return {
message: 'Hello from mixin',
name: 'mixin'
}
}
}
new Vue({
mixins: [mixin],
data() {
return {
message: 'Hello from component',
age: 18
}
},
created() {
console.log(this.message)
console.log(this.name)
console.log(this.age)
}
})
输出:
Hello from component
mixin
18
组件的 message 覆盖了混入的 message,而 name 和 age 则被合并。
同名钩子函数将合并为一个数组,都会被调用,且混入的钩子先于组件钩子调用:
const mixin = {
created() {
console.log('mixin created')
}
}
new Vue({
mixins: [mixin],
created() {
console.log('component created')
}
})
输出:
mixin created
component created
const mixin1 = {
created() {
console.log('mixin1 created')
}
}
const mixin2 = {
created() {
console.log('mixin2 created')
}
}
new Vue({
mixins: [mixin1, mixin2],
created() {
console.log('component created')
}
})
输出:
mixin1 created
mixin2 created
component created
值为对象的选项,如 methods、components、directives 等,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对:
const mixin = {
methods: {
foo() {
console.log('mixin foo')
},
bar() {
console.log('mixin bar')
}
}
}
new Vue({
mixins: [mixin],
methods: {
foo() {
console.log('component foo')
},
baz() {
console.log('component baz')
}
},
mounted() {
this.foo()
this.bar()
this.baz()
}
})
输出:
component foo
mixin bar
component baz
组件的 foo 覆盖了混入的 foo,而 bar 和 baz 则被合并。
计算属性的合并规则与方法相同:
const mixin = {
computed: {
mixedComputed() {
return 'from mixin'
}
}
}
new Vue({
mixins: [mixin],
computed: {
mixedComputed() {
return 'from component'
},
ownComputed() {
return 'own property'
}
},
created() {
console.log(this.mixedComputed)
console.log(this.ownComputed)
}
})
输出:
from component
own property
watch 选项的合并策略与钩子函数类似,合并为数组:
const mixin = {
watch: {
value(newVal) {
console.log('mixin watch:', newVal)
}
}
}
new Vue({
mixins: [mixin],
data() {
return {
value: 0
}
},
watch: {
value(newVal) {
console.log('component watch:', newVal)
}
},
mounted() {
this.value = 1
}
})
输出:
mixin watch: 1
component watch: 1
const mixin = {
components: {
MyButton: {
template: '<button>Mixin Button</button>'
}
},
directives: {
'mixin-focus': {
inserted(el) {
el.focus()
}
}
}
}
new Vue({
mixins: [mixin],
components: {
MyButton: {
template: '<button>Component Button</button>'
}
},
directives: {
'component-focus': {
inserted(el) {
el.focus()
}
}
}
})
| 选项类型 | 合并策略 | 冲突处理 |
|---|---|---|
| data | 递归合并 | 组件优先 |
| 钩子函数 | 合并为数组 | 都执行,混入先 |
| methods | 合并为对象 | 组件优先 |
| computed | 合并为对象 | 组件优先 |
| watch | 合并为数组 | 都执行,混入先 |
| components | 合并为对象 | 组件优先 |
| directives | 合并为对象 | 组件优先 |
const mixin = {
data() {
return {
message: 'mixin message',
count: 0
}
},
computed: {
doubleCount() {
return this.count * 2
}
},
methods: {
increment() {
this.count++
},
greet() {
console.log('mixin greet')
}
},
watch: {
count(newVal) {
console.log('mixin watch count:', newVal)
}
},
created() {
console.log('mixin created')
}
}
new Vue({
mixins: [mixin],
data() {
return {
message: 'component message',
name: 'Vue'
}
},
computed: {
tripleCount() {
return this.count * 3
}
},
methods: {
greet() {
console.log('component greet')
}
},
watch: {
count(newVal) {
console.log('component watch count:', newVal)
}
},
created() {
console.log('component created')
console.log('message:', this.message)
console.log('name:', this.name)
console.log('count:', this.count)
console.log('doubleCount:', this.doubleCount)
console.log('tripleCount:', this.tripleCount)
this.greet()
this.increment()
}
})
输出:
mixin created
component created
message: component message
name: Vue
count: 0
doubleCount: 0
tripleCount: 0
component greet
mixin watch count: 1
component watch count: 1
理解选项合并规则后,接下来学习全局混入。