1. VNode是什么及其作用
使用js对象来描述真是DOM,把DOM的标签,属性,内容都变成对象的属性。模板编译整个过程就是将template描述成VNode,经过一系列操作形成真实DOM,它的好处有两点
- 兼容性强,不受执行环境的影响。VNode因为是js对象,不管是Node环境还是浏览器环境,都可以统一操作,从而获得了SSR,原生渲染等能力
- 减少DOM操作,任何页面的变化,都是用VNode进行操作对比,只需要在最后一步挂载更新DOM即可
2. VNode如何生成
Vue内部,有一个专门的VNode类来实现VNode
function VNode(
tag, data, children,
text, elm, context,
componentOptions
) {
this.tag = tag; // 标签名
this.data = data;
this.children = children; // 子元素
this.text = text; // 文本内容
this.elm = elm; // Dom 节点
this.context = context;
this.componentOptions = componentOptions;
this.componentInstance = undefined;
this.parent = undefined;
this.isStatic = false; // 是否静态节点
this.isComment = false; // 是否是注释节点
this.isCloned = false; // 是否克隆节点
};
比如下面这段html会生成如下的VNode
<div class="parent">1111</div>
// 生成如下VNode
{
tag: 'div',
data: {
staticClass: 'parent'
},
children: [{
tag: undefined,
text: '1111'
}]
}
3. VNode存放了什么信息
- data data内部存储了节点的属性,class, style, 存储了绑定的事件
- elm 真实DOM节点,生成VNode时并不存在真实DOM
- context 渲染模板的上下文对象
- isStatic 是否是静态节点,当一个节点被标记为静态节点时,说明这个几点可不用去更新它了。当数据发生变化时,可以忽略对比
- parent 组件的外壳节点
- componentInstance 组件生成的实例
- componentOptions 这里用来存储父子组件通信的参数
4. VNode如何生成
在初始化选项,解析完模板之后,就需要挂载DOM了。此时就需要生成VNode了。挂载 DOM 第一步,就是先执行渲染函数,得到整个模板的 VNode
function (){
with(this){
// _c函数的作用就是返回VNode
return _c('div',{attrs:{"href":"xxxx"}},["1111"]).
}
}
vm._c = function(a, b, c, d) {
return createElement(vm, a, b, c, d, false);
};
function createElement(
context, tag, data,
children, normalizationType
) {
var vnode;
if (tag是正常html标签) {
vnode = new VNode(
tag, data, children, undefined,
undefined, context
);
}
else if (tag 是组件) {
vnode = createComponent(
Ctor, data, context,
children, tag
);
}
return vnode
}
正常标签和组件会走不同的流程,如果是标签,那直接新建VNode, 如果是组件,需要调用createComponent
function createComponent(
Ctor, data, context,
children, tag
) {
// extractPropsFromVNodeData 作用是把传入data的 attr 中属于 props的筛选出来
var propsData = extractPropsFromVNodeData(data, Ctor, tag);
var vnode = new VNode(
("vue-component-" + (Ctor.cid) + tag),
data, undefined, undefined, undefined,
context, {
Ctor: Ctor,
// 父组件给子组件绑定的props
propsData: propsData,
// 父组件给子组件绑定的事件
listeners: listeners,
tag: tag,
children: children
});
return vnode
}
5.VNode存放在哪
_vnode
存放当前节点的VNode,也就是可以通过这个VNode直接映射成当前真实DOM,主要作用是用来对比更新,当数据变化,会生成一个新的VNode,新的VNode和这个_node
做对比。$vnode
只有组件实例才有,因为 $vnode 存放的是外壳节点,页面实例中是不存在 $vnode 的
function updateChildComponent(
vm, parentVnode
) {
vm.$options._parentVnode = parentVnode;
vm.$vnode = parentVnode;
if (vm._vnode) {
vm._vnode.parent = parentVnode;
}
}