虚拟DOM与VNode
VNode是虚拟DOM节点的数据结构,包含 tag、data、children 等属性,通过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 }
通过 tag、text、isComment 等属性区分节点类型。
创建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是纯数据对象,包含
tag、data、children、elm等属性 - 通过
tag/text/isComment区分元素、文本、注释等节点类型 createElement/createTextVNode/createEmptyVNode创建不同类型VNode- VNode通过
elm属性关联真实DOM,patch过程建立映射 - 组件VNode包含
componentOptions和componentInstance cloneVNode复用data和children引用,只创建新实例
📝 发现内容有误?点击此处直接编辑