创建组件VNode
<div>
<test></test>
</div>
上面这个页面被解析成了一个渲染函数
function() {
with(this) {
return _c('div', [
_c('test')
])
}
}
这个_c
就是创建VNode的入口,也就是实际上的_createElement函数
function _createElement(
context, tag, data, children
) {
var vnode;
var options = context.$options
// 从父组件选项上拿到 对应的组件的选项
var Ctor = options.components[tag]
if (正常的HTML标签) { ....直接新建VNode }
else if ( Ctor ) {
vnode = createComponent(
Ctor, data, context,
children, tag
);
}
return vnode
}
如果是组件的话,会走createElement的逻辑
function createComponent(
Ctor, data, context,
children, tag
) {
// context.$options._base; 其实就是Vue
var baseCtor = context.$options._base;
// 创建组件构造函数
Ctor = baseCtor.extend(Ctor);
// 创建组件的外壳VNode
var vnode = new VNode(
"vue-component-" + (Ctor.cid) + name,
data, undefined, undefined,
undefined, context,
{
Ctor: Ctor
}
);
return vnode
}
来看看baseCtor.extend
也就是Vue.extend
做了什么
Vue.extend = function(extendOptions) {
// this 指向Vue
var Super = this;
var Sub = function VueComponent(options) {
this._init(options);
};
// 原型链继承
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
// Super 永远是 Vue,所以这里就是 合并全局选项
// 现在 Super 就是 vue,把 Vue 和 Sub 合并
// 是把一些全局的组件 指令合并到 Sub 中
Sub.options = mergeOptions(
// optios 还包括 mixins 注入的全局
Super.options,
extendOptions
);
return Sub
};
Component 创建 外壳节点的流程,总结如下
1页面渲染函数执行
2_c(‘test’) 执行
3createElement 碰到 tag 是一个组件
4从父组件中,拿到 test 组件的options,传入 createComponent (作用是创建构造函数和 VNode)
5createComponent 调用 Vue.extend 创建组件构造函数
6新建 VNode,并把构造函数和父组件给子组件的数据保存进去
7返回 VNode