Vue 版本:v2.6.11
文件夹结构
src
- compiler # 编译【暂定不展开】涉及到 mount 挂载
- global-api # 全局方法
- assets.js
- extend.js
- index.js
- mixin.js
- use.js
- core # 核心代码
- components #组件
- global-api #公共api
- instance #实例
- render-helpers
- event.js #初始化事件
- index.js #实例 Vue
- init.js #给实例的属性添加方法、生命周期初始化等,然后再调用原型链上的_mount 方法进一步解析 HTML,再根据 ast 树渲染虚拟 dom
- inject.js
- lifecycle.js #生命钩子函数添加进实例
- proxy.js #具体不知道,只知道多了 proxy 方法
- render.js #实例添加方法、Vue的原型链上添加 _render 渲染函数,然后创建虚拟 dom
- state.js #初始化实例的 props、methods、data、computed、watch
- observer #观察
- array.js #数组的处理
- dep.js #收集依赖
- index.js
- scheduler.js
- traverse.js
- watcher.js #watcher 类
- util #工具函数
- vdom #虚拟 dom
- helpers
- modules
- create-components.js
- create-element.js #_render 渲染时会调用它,然后根据逻辑判断生成 VNode
- create-functional-components.js
- patch.js #虚拟 dom => 真实 dom
- vnode.js #虚拟 dom 的各个属性添加、创建不同虚拟 dom 的方法
- config.js
- index.js
- platforms # 不同平台的支持(web、小程序)
- server # 服务端渲染
- sfc # .vue 文件解析
- shared # 公共方法
Vue 的文件一目了然,但是实际上阅读时会有点绕圈子,要时不时返回去看看。
global-api
它给 Vue 对象添加了 util、set、delete、nextTick、options 等属性对象,再依次调用 extend、initUse 等方法。本次研究对象是 component,因为 Vue 的其中一个重要特点就是组件化。
Vue.extend
在看 Vue.options.component 时要先看到 initExtend 方法,在[global-api/extend.js]文件夹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
53function initExtend (Vue: GlobalAPI) {
Vue.cid = 0
let cid = 1
Vue.extend = function (extendOptions: Object): Function {
extendOptions = extendOptions || {}
const Super = this
const SuperId = Super.cid
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
if (cachedCtors[SuperId]) {
return cachedCtors[SuperId]
}
const name = extendOptions.name || Super.options.name
if (process.env.NODE_ENV !== 'production' && name) {
validateComponentName(name)
}
// 创建了 VueComponent 构造方法,目的是继承 Vue 原型链上的方法属性。
const Sub = function VueComponent (options) {
this._init(options)
}
// 这里的 Object.create() 是浅拷贝
Sub.prototype = Object.create(Super.prototype)
// 但是它的原型还是要指向自己
Sub.prototype.constructor = Sub
Sub.cid = cid++
Sub.options = mergeOptions(
Super.options,
extendOptions
)
Sub['super'] = Super
if (Sub.options.props) {
initProps(Sub)
}
if (Sub.options.computed) {
initComputed(Sub)
}
// 下面就是 VueComponent 也要拥有 Vue 本身的方法
Sub.extend = Super.extend
Sub.mixin = Super.mixin
Sub.use = Super.use
ASSET_TYPES.forEach(function (type) {
Sub[type] = Super[type]
})
if (name) {
Sub.options.components[name] = Sub
}
Sub.superOptions = Super.options
Sub.extendOptions = extendOptions
Sub.sealedOptions = extend({}, Sub.options)
cachedCtors[SuperId] = Sub
return Sub
}
}
因此 Vue.extend 返回的是一个 VueComponent 方法,并且它拥有了 Vue 原型链上的方法。
Vue.options.component 方法
Vue.options 上有3个对象,分别是component、directive 和 filter。
它还继续调用 initAssetRegisters 方法,给 Vue.options.component 添加了方法。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
26initAssetRegisters (Vue: GlobalAPI) {
ASSET_TYPES.forEach(type => {
Vue[type] = function (
id: string,
definition: Function | Object
): Function | Object | void {
if (!definition) {
return this.options[type + 's'][id]
} else {
if (process.env.NODE_ENV !== 'production' && type === 'component') {
validateComponentName(id)
}
if (type === 'component' && isPlainObject(definition)) {
definition.name = definition.name || id
// this.options._base 指的是 Vue
definition = this.options._base.extend(definition)
}
if (type === 'directive' && typeof definition === 'function') {
definition = { bind: definition, update: definition }
}
this.options[type + 's'][id] = definition
return definition
}
}
})
}
这里有2个参数,id、definition,通过调用 Vue.extend 方法将 definition 转化为 VueComponent 对象,并存入 Vue.options.components 里。
这样就做成了一个组件的库了。