全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-20 10 分钟 ✍️ juanwangdev

虚拟DOM与VNode

VNode是虚拟DOM节点的数据结构,包含 tagdatachildren 等属性,通过diff算法最小化真实DOM操作。

VNode类定义

JavaScript
class VNode {
  constructor(
    tag?: string,
    data?: VNodeData,
    children?: ?Array<VNode>,
    text?: string,
    elm?: Node,
    context?: Component,
    componentOptions?: VNodeComponentOptions,
    asyncFactory?: Function
  ) {
    this.tag = tag                // 标签名
    this.data = data              // 属性、事件、指令等
    this.children = children      // 子VNode数组
    this.text = text              // 文本内容
    this.elm = elm                // 对应真实DOM节点
    this.ns = undefined           // 命名空间
    this.context = context        // 组件上下文
    this.fnContext = undefined    // 函数式组件上下文
    this.fnOptions = undefined    // 函数式组件选项
    this.fnScopeId = undefined    // 函数式组件作用域ID
    this.key = data && data.key   // 唯一标识
    this.componentOptions = componentOptions  // 组件选项
    this.componentInstance = undefined        // 组件实例
    this.parent = undefined       // 父VNode
    this.raw = false              // 是否原始HTML
    this.isStatic = false         // 是否静态节点
    this.isRootInsert = true      // 是否根插入
    this.isComment = false        // 是否注释节点
    this.isCloned = false         // 是否克隆节点
    this.isOnce = false           // 是否v-once节点
    this.asyncFactory = asyncFactory
    this.asyncMeta = undefined
    this.isAsyncPlaceholder = false
  }
}

VNode是纯数据对象,不操作真实DOM,通过 elm 属性关联真实节点。

VNode类型

JavaScript
// 元素节点
{ tag: 'div', data: {...}, children: [...], elm: DOMNode }

// 文本节点
{ text: 'hello', elm: TextNode }

// 注释节点
{ text: 'comment', isComment: true, elm: CommentNode }

// 组件节点
{ 
  tag: 'vue-component-1-MyComp',
  componentOptions: { Ctor, propsData, listeners },
  componentInstance: Component
}

// 空节点
{ text: '', isStatic: true }

通过 tagtextisComment 等属性区分节点类型。

创建VNode

JavaScript
// 创建元素VNode
function createElement(
  context: Component,
  tag: string,
  data: VNodeData,
  children: Array<VNode>
): VNode {
  if (Array.isArray(data)) {
    children = data
    data = undefined
  }
  
  // 处理组件
  if (isDef(data) && isDef(data.is)) {
    tag = data.is
  }
  
  return new VNode(tag, data, children, undefined, undefined, context)
}

// 创建文本VNode
function createTextVNode(val): VNode {
  return new VNode(undefined, undefined, undefined, String(val))
}

// 创建空VNode
function createEmptyVNode(text = ''): VNode {
  const node = new VNode()
  node.text = text
  node.isComment = true
  return node
}

不同节点类型调用不同创建函数,统一返回VNode实例。

VNode与真实DOM映射

JavaScript
// patch过程建立映射
function patch(oldVnode, vnode) {
  if (isRealElement(oldVnode)) {
    // 首次渲染: 创建真实DOM
    vnode.elm = document.createElement(vnode.tag)
    // 递归创建子节点
    vnode.children?.forEach(child => {
      vnode.elm.appendChild(createElm(child))
    })
  } else {
    // 更新: 复用DOM节点
    vnode.elm = oldVnode.elm
    // diff对比变化
    updateProperties(oldVnode, vnode)
  }
}

VNode通过 elm 属性关联真实DOM,patch过程建立和维护映射关系。

克隆VNode优化

JavaScript
function cloneVNode(vnode): VNode {
  const cloned = new VNode(
    vnode.tag,
    vnode.data,
    vnode.children,
    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.isCloned = true  // 标记为克隆
  return cloned
}

克隆VNode复用data和children引用,只创建新实例,提升性能。

要点总结

  • VNode是纯数据对象,包含 tagdatachildrenelm 等属性
  • 通过 tag/text/isComment 区分元素、文本、注释等节点类型
  • createElement/createTextVNode/createEmptyVNode 创建不同类型VNode
  • VNode通过 elm 属性关联真实DOM,patch过程建立映射
  • 组件VNode包含 componentOptionscomponentInstance
  • cloneVNode 复用data和children引用,只创建新实例

📝 发现内容有误?点击此处直接编辑

← 上一篇 组件实例化与挂载流程
下一篇 → KeepAlive与缓存机制底层实现
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库