主题
源码分析-父子类合并策略
1. 基本概念
1.1 什么是合并策略
合并策略是Vue在处理父子组件选项时使用的一套规则系统,用于决定如何合并父组件和子组件的各种选项(data、methods、computed等)。
1.2 合并策略的意义
- 确保组件继承的正确性
- 维护数据的响应式
- 避免命名冲突
- 优化性能
2. 核心实现
2.1 合并选项
js
// src/core/util/options.js
const strats = config.optionMergeStrategies
// 默认策略
const defaultStrat = function(parentVal, childVal) {
return childVal === undefined
? parentVal
: childVal
}
// 数据合并策略
strats.data = function(parentVal, childVal, vm) {
if (!vm) {
if (childVal && typeof childVal !== 'function') {
warn('data option should be a function.')
return parentVal
}
return mergeDataOrFn(parentVal, childVal)
}
return mergeDataOrFn(parentVal, childVal, vm)
}
2.2 生命周期钩子合并
js
// 生命周期钩子合并策略
function mergeHook(parentVal, childVal) {
const res = childVal
? parentVal
? parentVal.concat(childVal)
: Array.isArray(childVal)
? childVal
: [childVal]
: parentVal
return res
? dedupeHooks(res)
: res
}
LIFECYCLE_HOOKS.forEach(hook => {
strats[hook] = mergeHook
})
3. 具体策略分析
3.1 data合并
js
// data合并示例
const Parent = {
data() {
return {
message: 'parent'
}
}
}
const Child = {
data() {
return {
title: 'child',
message: 'override'
}
}
}
// 最终合并结果
{
message: 'override',
title: 'child'
}
3.2 methods合并
js
// methods合并策略
strats.methods = function(parentVal, childVal) {
if (!parentVal) return childVal
const ret = Object.create(null)
extend(ret, parentVal)
if (childVal) extend(ret, childVal)
return ret
}
4. 高级特性
4.1 自定义合并策略
js
// 自定义选项合并策略
Vue.config.optionMergeStrategies.myOption = function(parentVal, childVal) {
return childVal ? childVal.concat(parentVal) : parentVal
}
// 使用示例
const Parent = {
myOption: ['parent']
}
const Child = {
myOption: ['child']
}
// 合并结果: ['child', 'parent']
4.2 Mixins合并
js
// mixins合并示例
const mixin = {
created() {
console.log('mixin created')
}
}
export default {
mixins: [mixin],
created() {
console.log('component created')
}
}
5. 实际应用
5.1 组件继承
js
// 基础组件
const BaseComponent = {
data() {
return {
loading: false
}
},
methods: {
baseMethod() {
// 基础方法
}
}
}
// 继承组件
export default {
extends: BaseComponent,
data() {
return {
title: 'Extended Component'
}
}
}
5.2 全局混入
js
// 全局mixin
Vue.mixin({
created() {
const options = this.$options
if (options.store) {
this.$store = options.store
} else if (options.parent && options.parent.$store) {
this.$store = options.parent.$store
}
}
})
6. 性能优化
6.1 缓存策略
js
// 缓存合并结果
function mergeOptions(parent, child, vm) {
const key = parent.key + child.key
const cache = vm.$options._cache
if (cache[key]) {
return cache[key]
}
const ret = mergeData(parent, child)
cache[key] = ret
return ret
}
6.2 延迟合并
js
// 延迟数据合并
function deferredMerge(parentVal, childVal) {
return () => {
const parent = typeof parentVal === 'function'
? parentVal.call(this)
: parentVal
const child = typeof childVal === 'function'
? childVal.call(this)
: childVal
return mergeData(parent, child)
}
}
7. 调试技巧
7.1 追踪合并过程
js
// 开发环境下的合并追踪
if (process.env.NODE_ENV !== 'production') {
strats.data = function(parentVal, childVal, vm) {
if (!vm) {
console.log('Merging data:', { parentVal, childVal })
}
return mergeDataOrFn(parentVal, childVal, vm)
}
}
7.2 合并冲突检测
js
function checkConflict(parentVal, childVal, key) {
if (parentVal && childVal && parentVal[key] && childVal[key]) {
console.warn(`Duplicate key detected: ${key}`)
}
}
8. 注意事项
- 避免深层次的继承
- 合理使用mixins
- 注意命名冲突
- 关注性能影响
- 保持选项的纯函数特性