刺猬猫阅读免费下载
126.01MB · 2025-10-14
在 Vue 开发中,你是否使用过:
import BaseComponent from './base';
import { formMixin } from './mixins';
export default {
extends: BaseComponent,
mixins: [formMixin, authMixin],
// ...
}
本文将从 源码级 mergeOptions
到 实战合并规则,彻底解析 Vue 组件选项的合并逻辑。
特性 | mixins | extends |
---|---|---|
类型 | 数组(多个混入) | 单个对象或组件 |
用途 | 横向复用逻辑(如表单、权限) | 纵向继承(扩展基类组件) |
合并顺序 | 从前到后依次合并 | 先合并 extends |
优先级 | 组件自身 > mixins > extends | 组件自身 > mixins > extends |
mergeOptions
function mergeOptions(parent, child, vm) {
// 1. 规范化选项(props/inject/directives)
normalizeProps(child, vm);
normalizeInject(child, vm);
normalizeDirectives(child, vm);
// 2. 先处理 extends
if (child.extends) {
parent = mergeOptions(parent, child.extends, vm);
}
// 3. 再处理 mixins
if (child.mixins) {
for (let i = 0, l = child.mixins.length; i < l; i++) {
const mixin = child.mixins[i];
parent = mergeOptions(parent, mixin, vm);
}
}
// 4. 最后合并当前组件选项
const options = {};
for (const key in parent) {
mergeField(key);
}
for (const key in child) {
if (!hasOwn(parent, key)) {
mergeField(key);
}
}
function mergeField(key) {
// 根据 key 调用不同的合并策略
const strat = strats[key] || defaultStrat;
options[key] = strat(parent[key], child[key], vm, key);
}
return options;
}
created
、mounted
等)extends
→ mixins
(从前到后) → 组件自身。// base.js
export default {
created() { console.log('Base created'); }
}
// mixin.js
export const logMixin = {
created() { console.log('Mixin created'); }
}
// Component.vue
export default {
extends: BaseComponent,
mixins: [logMixin],
created() { console.log('Component created'); }
}
输出:
Base created
Mixin created
Component created
data
函数parent.data()
和 child.data()
,并 浅合并(shallow merge) 结果。// extends
data() { return { a: 1, b: 2 } }
// mixins
data() { return { b: 3, c: 4 } }
// 组件自身
data() { return { c: 5, d: 6 } }
最终 data
:
{ a: 1, b: 3, c: 5, d: 6 }
methods
、computed
、watch
// mixin
methods: { save() { console.log('Mixin save'); } }
// 组件
methods: { save() { console.log('Component save'); } }
调用 this.save()
时,执行的是 组件自身的 save
。
props
、inject
、directives
mixins
和 extends
。// extends
props: { type: String, required: true }
// 组件
props: { type: Number } // 覆盖 type,但 required 仍存在
components
、filters
(Vue 2)// mixin
components: { Button: ButtonA }
// 组件
components: { Button: ButtonB } // 覆盖
const Base = {
name: 'Base',
data() { return { base: 1, shared: 'base' }; },
created() { console.log('Base'); }
};
const Mixin1 = {
name: 'Mixin1',
data() { return { mixin1: 2, shared: 'mixin1' }; },
created() { console.log('Mixin1'); }
};
const Mixin2 = {
name: 'Mixin2',
data() { return { mixin2: 3 }; },
created() { console.log('Mixin2'); }
};
export default {
extends: Base,
mixins: [Mixin1, Mixin2],
data() { return { component: 4, shared: 'component' }; },
created() { console.log('Component'); }
}
最终选项:
选项 | 值 |
---|---|
name | 'Component' (组件自身覆盖) |
data | { base:1, shared:'component', mixin1:2, mixin2:3, component:4 } |
created | [Base.created, Mixin1.created, Mixin2.created, Component.created] |
created
执行顺序:
Base
Mixin1
Mixin2
Component
mixins
:用于横切关注点(如日志、权限、表单验证);extends
:用于创建基类组件(如 BaseForm
、BaseTable
);data
浅合并:嵌套对象不会递归合并;methods
被静默覆盖;mixins
导致钩子执行顺序难追踪。合并源 | 处理顺序 | 优先级 |
---|---|---|
extends | 1 | 中 |
mixins | 2(从前到后) | 中 |
组件自身 | 最后 | 高 |
选项类型 | 合并策略 |
---|---|
生命周期 | 数组,依次执行 |
data | 浅合并返回值 |
methods | 直接覆盖 |
props | 浅合并对象 |
掌握这一机制,你就能:
预测组件行为;
设计可复用的 mixin
;
避开合并陷阱;
平滑迁移到 Composition API。