render
在之前的首次渲染中我们知道,mountComponent
方法中,会调用new Watcher
作为首次渲染的wacher,而它传入的方法 updateComponent
中的回调就是dom更新的入口
updateComponent = () => {
vm._update(vm._render(), hydrating)
}
1
2
3
2
3
找到了入口,我们就可以看到它调用了vm._render
, 而它就是实例上的_render
方法,我们在_init
方法中的initRender
进行了声明 ,看以下代码,我们能找到vm.$createElement
// 对编译生成的render进行渲染方法
vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
// 对手写的render函数进行渲染的方法
vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
1
2
3
4
2
3
4
Vue.prototype._render = function (): VNode {
const vm: Component = this
// 获取实例上options里的render方法
const { render, _parentVnode } = vm.$options
vm.$vnode = _parentVnode
// render self
let vnode
try {
currentRenderingInstance = vm
// 调用render,传入 vm 和vm.$createElement
// vm._renderProxy 就是vm,这个在_init中有定义
vnode = render.call(vm._renderProxy, vm.$createElement)
} catch (e) {
handleError(e, vm, `render`)
if (process.env.NODE_ENV !== 'production' && vm.$options.renderError) {
try {
vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e)
} catch (e) {
handleError(e, vm, `renderError`)
vnode = vm._vnode
}
} else {
vnode = vm._vnode
}
} finally {
currentRenderingInstance = null
}
// 如果是array
if (Array.isArray(vnode) && vnode.length === 1) {
vnode = vnode[0]
}
// return empty vnode in case the render function errored out
if (!(vnode instanceof VNode)) {
if (process.env.NODE_ENV !== 'production' && Array.isArray(vnode)) {
warn(
'Multiple root nodes returned from render function. Render function ' +
'should return a single root node.',
vm
)
}
vnode = createEmptyVNode()
}
// set parent
vnode.parent = _parentVnode
return vnode
}
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
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