此处考虑 *.vue
单文件第一次 render 的情况。
- 每个
*.vue
都会被 vue-loader 编译成一个对象,姑且称为 options,<template></template>
包含的部分被编译成render() {}
方法,内容形式如下:
const render = function() {
var _vm = this
var _h = _vm.$createElement
var _c = _vm._self._c || _h
return _c(
"div",
{ attrs: { id: "app" } },
[_c("home"), _c("div", [_vm._v(_vm._s(_vm.ll))]), _vm._v("\n lalal\n")],
1
)
}
options 会被用于传进 Vue.extend(options)
里生成一个继承 Vue 的子类,比如叫 VueComponent,然后这个 VueComponent 被用来生成 vm。VueComponent 跟 Vue 接受一样的参数,实例化时也跟 Vue 实例化做一样的事情:调用 this._init(options)
- 为了实现组件系统,除了 HTML 的 element、comment、text 类型的 vNode 以外,Vue 里新增了一种与 vm 对应的 component vNode,比如上面的
_c('home')
的返回值就是一个根据 home 组件的生成的 component vNode - vNode 被转换成 node 挂载到 parentElm 上是调用
vm.__patch__(oldVNode, vNode)
结果,完成挂载动作的是createElm(vNode, insertedVNode, parentElm)
(当然,最终肯定是因为调用了parentElm.appendChild(vNode.elm)
)。当传入createElm
的 vNode 为非 component vNode 时(同时假定这个 vNode 对应一个叶子 node),调用完成后,根据这个 vNode 创建的 node 会被直接插入 parentElm。当是一个 component vNode 时,会由上面提到的 VueComponent 生成一个与之对应的 vm 并执行vm.$mount()
,在此过程中,会调用vm.__patch__(undefined, realVNode = vm.render())
然后再次执行createElm(realVNode, insertedVNodeQueue, parentElm)
,这才将根据 realVNode(假设 realNode 本身及其 children 所有的 vNode 都不是 component vNode,否则依然为存在的 component vNode 生成 vm,并挂载) 创建的 node 插入到 parentElm。