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:{...}}
