0%

Vue源码解读(初始化Init时组件配置项处理)

Vue 源码解读(初始化 Init 时组件配置项处理)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
export function initMixin(Vue: Class<Component>) {
Vue.prototype._init = function (options?: Object) {
const vm: Component = this
// a uid
vm._uid = uid++

let startTag, endTag
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
startTag = `vue-perf-start:${vm._uid}`
endTag = `vue-perf-end:${vm._uid}`
mark(startTag)
}

// a flag to avoid this being observed
vm._isVue = true


// merge options
// 处理组件配置项
if (options && options._isComponent) {
// optimize internal component instantiation
// since dynamic options merging is pretty slow, and none of the
// internal component options needs special treatment.
/**
* 每个子组件初始化时走这里,这里只做了一些性能优化
* 将组件配置对象上的一些深层次属性放到 vm.$options 选项中,以提高代码的执行效率
*/
initInternalComponent(vm, options)
} else {
/**
* 初始化根组件时走这里,合并 Vue 的全局配置到根组件的局部配置,比如 Vue.component 注册的全局组件会合并到 根实例的 components 选项中
* 至于每个子组件的选项合并则发生在两个地方:
* 1、Vue.component 方法注册的全局组件在注册时做了选项合并
* 2、{ components: { xx } } 方式注册的局部组件在执行编译器生成的 render 函数时做了选项合并,包括根组件中的 components 配置
*/
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
}
......
}
}

export function resolveConstructorOptions(Ctor: Class<Component>) {
// 默认配置在 initGlobalAPI 中定义 src\core\global-api\index.js
let options = Ctor.options

if (Ctor.super) {
// Vue.extend 构建的子类或者子类 Sub.extend 构建的子类都有 super 属性,指向父类
const superOptions = resolveConstructorOptions(Ctor.super)
// Vue.extend 创建子类时,superOptions 是保存父类默认配置的引用,通常情况下,Sub.superOptions === Father.options,但是如果父类使用 mixin 则会改变自身的 options(另一个对象,内存地址不一样)
const cachedSuperOptions = Ctor.superOptions
// 对比默认配置是否已经改变,如果父类默认有改变,则子类也跟着变化(为什么要跟着变化?因为 Vue.mixin 是属于全局混入,如果不跟着变化,子类就无法获取mixin数据 )
/**
* 为啥 Vue 默认配置会变化
* 如:Vue.extend 后 Vue.mixin 改变父类的默认配置,这个时候就需要更新子类的配置
*
* const Vloading = Vue.extend({ ... }); // Vloading.superOptions 保留对父类默认配置(Vue.options)的引用
* Vue.mixin({ ... }); // Vue.mixin 会修改默认配置(Vue.options变化),相对于 Vloading 来说,这里父类的默认配置就变化了
* new Vloading({ ... }); // 子类初始化时,需要获取上面 mixin 的数据就必须更新子类的配置
*/
if (superOptions !== cachedSuperOptions) {
// super option changed,
// need to resolve new options.
// 说明基类构造函数选项已经发生改变,需要重新设置
Ctor.superOptions = superOptions
// check if there are any late-modified/attached options (#4976)
// 检查 Ctor.options 上是否有任何后期修改/附加的选项(#4976)
// 提取 mixin 前后 options 的差异
const modifiedOptions = resolveModifiedOptions(Ctor)
// update base extend options
if (modifiedOptions) {
// extendOptions 是构建子类时 Vue.extend(extendOptions) 传入的配置,这里将差异合并到 extendOptions,这样子类多次实例化就只需要第一次合并即可
extend(Ctor.extendOptions, modifiedOptions)
}
// 重新生成子类的 options,使用最新的父类默认配置 + Vue.extend创建子类时传入的配置(extendOptions)
options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)
if (options.name) {
// 注册组件,递归组件专用
options.components[options.name] = Ctor
}
}
}
return options
}