Vue 进阶系列丨虚拟DOM和VNode
提供与真实 DOM 节点所对应的虚拟节点 vnode
将新的虚拟节点和旧的虚拟节点进行对比,然后更新页面
class VNode {
constructor (
tag,
data,
children,
text,
elm,
context,
componentOptions,
asyncFactory
) {
this.tag = tag;
this.data = data;
this.children = children;
this.text = text;
this.elm = elm;
this.ns = undefined;
this.context = context;
this.fnContext = undefined;
this.fnOptions = undefined;
this.fnScopeId = undefined;
this.key = data && data.key;
this.componentOptions = componentOptions;
this.componentInstance = undefined;
this.parent = undefined;
this.raw = false;
this.isStatic = false;
this.isRootInsert = true;
this.isComment = false;
this.isCloned = false;
this.isOnce = false;
this.asyncFactory = asyncFactory;
this.asyncMeta = undefined;
this.isAsyncPlaceholder = false;
}
get child () {
return this.componentInstance
}
}
注释节点
const createEmptyVNode = (text = '') => {
const node = new VNode();
node.text = text;
node.isComment = true;
return node
};
我们可以看到注释节点只有两个有效属性,text 和 isComment,其余属性都是默认的 undefined 或者 false。
例如,一个真实的注释节点:
<!-- 注释节点 -->
所对应的 vnode 是这样的:
{
text:'注释节点',
isComment:true
}
文本节点
function createTextVNode (val) {
return new VNode(undefined, undefined, undefined, String(val))
}
文本节点只有一个 text 属性,它的 vnode 是这样的:
{
text:'我是文本内容',
}
克隆节点
function cloneVNode (vnode) {
const cloned = new VNode(
vnode.tag,
vnode.data,
vnode.children && vnode.children.slice(),
vnode.text,
vnode.elm,
vnode.context,
vnode.componentOptions,
vnode.asyncFactory
);
cloned.ns = vnode.ns;
cloned.isStatic = vnode.isStatic;
cloned.key = vnode.key;
cloned.isComment = vnode.isComment;
cloned.fnContext = vnode.fnContext;
cloned.fnOptions = vnode.fnOptions;
cloned.fnScopeId = vnode.fnScopeId;
cloned.asyncMeta = vnode.asyncMeta;
cloned.isCloned = true;
return cloned
}
克隆节点就是将一个节点的内容全部复制到新的节点中。主要用来优化静态节点和插槽节点。当静态节点需要重新渲染的时候,并不需要重新再次走一遍渲染函数,然后重新生成 vnode,只需要使用克隆节点的方法将之前的 vnode 克隆一份即可,一定程度上优化了程序的性能。
克隆节点和被克隆节点的唯一区别是 isCloned 属性,克隆节点的 isCloned为 true,被克隆的原始节点的 isCloned 为 false。
元素节点
元素节点一般包含 4 个有效属性:
tag:就是节点的名称,例如 div、p、img
data:该属性包含一些节点上的数据,例如 class、style
children:该节点的子节点列表
context:当前组件的 vue.js 实例
通常,函数式组件的 vnode 是这样子的:
{
children:[VNode,VNode],
context:{...},
data:{...},
tag:{...}
}
组件节点
和元素节点类似,有两个独有的属性 componentInstance 和 componentOptions。
通常,函数式组件的 vnode 是这样子的:
{
{...}, :
{...}, :
context:{...},
data:{...},
tag:{...}
}
函数式组件
和组件节点类似,有两个独有的属性 functionalContext 和 functionalOptions。
通常,函数式组件的 vnode 是这样子的:
{
functionalContext :{...},
functionalOptions:{...},
context:{...},
data:{...},
tag:{...}
}