vnode 是用 javascript 对象描述 dom 节点的“说明书”,核心字段包括 type、props、children 和可选 key;它不操作真实 dom,仅声明结构与属性。

VNode 就是一个用 JavaScript 对象写的“DOM 节点说明书”——它不操作真实 DOM,也不绑定事件,只专注描述:这是什么标签、带哪些属性、里面有什么内容、子节点长什么样。
VNode 的核心字段有哪些
一个标准 VNode 至少包含这几个关键字段:
-
type:字符串(如
'div'、'span')或组件对象(如{ setup() { return () => h('p', 'Hello') } }) -
props:对象,存放属性和事件,比如
{ id: 'btn', class: 'primary', onClick: handleClick } - children:可以是字符串(文本节点)、数组(多个子 VNode)、null 或 undefined;不直接写 HTML 字符串
-
key(可选但重要):用于 diff 时精准识别节点,值需唯一且稳定,比如
key: 'item-123'
手写一个真实可用的 VNode 示例
假设你要描述这个 DOM:<button id="save" class="btn btn--large" disabled>保存</button>
对应的手动 VNode 写法如下:
const vnode = {
type: 'button',
props: {
id: 'save',
class: 'btn btn--large',
disabled: true
},
children: '保存',
key: 'save-btn'
}
注意:class 直接传字符串即可(Vue 会自动处理);disabled: true 会渲染为原生布尔属性,不需要写 'disabled' 字符串。
怎么让这个 VNode 变成真实 DOM?
你可以写一个极简 patch 函数来“兑现”它:
function patch(vnode, container) {
const el = document.createElement(vnode.type)
// 设置属性
if (vnode.props) {
Object.keys(vnode.props).forEach(key => {
const value = vnode.props[key]
if (key === 'class') {
el.className = value
} else if (key.startsWith('on')) {
el.addEventListener(key.slice(2).toLowerCase(), value)
} else {
el.setAttribute(key, value)
}
})
}
// 设置子内容
if (typeof vnode.children === 'string') {
el.textContent = vnode.children
}
container.appendChild(el)
return el
}
// 使用
const app = document.getElementById('app')
patch(vnode, app)
运行后,页面就会出现一个真实的 <button></button> 元素。这正是 Vue 渲染器最底层逻辑的简化还原。
常见误区提醒
别把 VNode 和真实 DOM 混为一谈:
- VNode 是纯数据对象,没有
innerHTML、addEventListener等 DOM 方法 - VNode 不持有
el引用(除非 patch 后手动挂载),它的el字段初始为null - 不要在 VNode 里写内联样式字符串,应传对象:
style: { color: 'red', fontSize: '14px' } - 子节点嵌套要保持结构清晰:文本节点用字符串,元素节点用新 VNode 对象,避免混写
children: '<span>xxx</span>'
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











