html:
组件页面渲染的基本流程main.js:
import Vue from "vue";
import Home from "./home.vue";
new Vue({
el: "#app",
template: "",
components: { Home }
});
home.vue
{{text}}
export default {
name: "home",
data() {
return {
text: '测试'
};
},
mounted() {
},
methods: {
}
};
运行时,home.vue中的template会被vue编辑器转换成render函数,并放到在home.vue文件默认导出的组件对象上。当某组件通过components引用home组件时,就是引用该组件对象。
编译器生成的render函数:
var render = function() {
var _vm = this
var _h = _vm.$createElement
var _c = _vm._self._c || _h
return _c(
"div",
{ staticClass: "home" },
[
_c("a",
[_vm._v(_vm._s(_vm.text))]
)
]
)
}
组件对象:
{
beforeCreate: []
beforeDestroy: []
data: function() {}
methods: {}
mounted: function() {}
name: "home"
render: function() {}
staticRenderFns: []
__file: "src/page/home/index.vue"
_compiled: true
}
组件渲染页面时会先调用render函数,render函数返回组件的VNode节点实例。每个标签(包括文本节点)生成VNode节点实例。先创建子标签的节点实例,并作为参数,在创建父标签的节点实例时将它添加到实例的children数组中,形成树形结构。
如果标签是组件标签,则会在components找到的组件对象,并使用extend方法生成组件的构造函数,并将组件对象保存在构造函数的options上。而构造函数会保存在组件标签的VNode节点实例上。
当render执行完成,返回的VNode节点实例作为参数,传入到patch方法中,patch会返回组件的根元素,并赋值给组件实例$el属性上。
在patch方法中,每个VNode实例生成对应的DOM元素,并保存在VNode实例的elm上。根据节点实例children保存的子节点,创建DOM元素,并添加到父元素中,形成DOM树。最后返回DOM树中的根元素。
如果是包含组件构造器的VNode节点实例,会先使用构造器创建组件实例,调用组件render方法,执行以上操作,生成VNode节点树,根据VNode节点树再生成DOM树,并将DOM树的根元素添加到父元素中,完成组件的页面渲染。
// 生成组件实例,并添加组件根标签到父标签中:
function createComponent (vnode, insertedVnodeQueue, parentElm, refElm) {
var i = vnode.data;
if (isDef(i)) {
var isReactivated = isDef(vnode.componentInstance) && i.keepAlive;
if (isDef(i = i.hook) && isDef(i = i.init)) {
i(vnode, false /* hydrating */);
}
// after calling the init hook, if the vnode is a child component
// it should've created a child instance and mounted it. the child
// component also has set the placeholder vnode's elm.
// in that case we can just return the element and be done.
if (isDef(vnode.componentInstance)) {
initComponent(vnode, insertedVnodeQueue);
insert(parentElm, vnode.elm, refElm);// 将组件根节点上的elm添加到父标签中。
if (isTrue(isReactivated)) {
reactivateComponent(vnode, insertedVnodeQueue, parentElm, refElm);
}
return true
}
}
}