虚拟DOM核心是组件逻辑与节点操作解耦:组件层仅通过VNode(含tag、props、children等字段)声明视图意图,不涉浏览器API;runtime层负责将VNode映射为真实节点,屏蔽平台差异,支撑跨端、SSR与可测试性。

虚拟 DOM 的设计核心之一,就是把组件逻辑和底层节点操作彻底分开。这种解耦不是为了代码好看,而是让 Vue 能在不同环境里复用同一套更新机制,同时让开发者专注状态与结构,不用操心 DOM 怎么挂、怎么删。
组件层只描述“要什么”
组件的模板或 render 函数产出的是 VNode——一个纯数据对象,含 tag、props、children、key 等字段,不带任何浏览器 API 调用。它不关心自己最终是否变成 <div> 还是 <canvas>,也不管事件是用 addEventListener 还是小程序的 bindtap 绑定。
- 一个按钮组件返回的 VNode,只是声明“我是一个 type=button 的元素,有 disabled 属性,子内容是‘提交’”
- 这个 VNode 可以被 Vue 的 runtime-dom 渲染成真实 DOM,也能被 runtime-mp-weixin 渲染成小程序节点
- 组件内部无需 import 任何 DOM 操作函数,也不依赖 document 或 window
节点层专注“怎么画”
runtime-dom 层拿到 VNode 后,才真正开始调用浏览器原生接口:创建元素、设置属性、插入子节点、绑定事件、处理 ref……所有这些动作都被封装在标准方法里,比如:
-
createElement('div')→ 返回 document.createElement('div') -
patchProp(el, 'class', null, 'active')→ 内部调用 el.className = 'active' -
insert(child, parent, anchor)→ 对应 parent.insertBefore(child, anchor)
这些方法屏蔽了浏览器兼容细节,也允许在非浏览器环境(如 Node.js 测试)中被 mock 替换,不影响组件本身运行。
解耦带来的实际效果
这种分离直接反映在开发体验和工程能力上:
- 写组件时,可以完全脱离 DOM 环境做单元测试,测的是 VNode 输出是否符合预期
- 升级 runtime-dom(比如优化 insert 性能或支持新 CSS 属性),组件代码零改动
- 跨平台扩展只需新增一个 runtime(如 canvas、WebGL),不用重写任何一个组件
- 服务端渲染(SSR)复用相同组件逻辑,只换掉节点创建方式(从 document 切到字符串拼接)
组件定义视图意图,VNode 承载结构契约,runtime 实现平台契约——三层之间靠稳定接口通信,不互相渗透。这正是 Vue 虚拟 DOM 能兼顾灵活性与可维护性的底层支撑。


















