0
点赞
收藏
分享

微信扫一扫

深入 Vue 3 渲染系统:runtime-dom 模块的设计与职责解析

(深入 Vue 3 渲染系统:runtime-dom 模块的设计与职责解析)

1. 概览:runtime-dom 在整个架构中的位置

Vue 3 的架构是高度模块化的。渲染逻辑被拆分为:

  • runtime-core:平台无关的渲染逻辑(patch、vnode、组件系统)
  • runtime-dom:浏览器平台专属渲染器(DOM 操作、属性 patch、事件绑定等)
  • @vue/compiler-dom:模板编译器(将 template 转换为 render 函数)

runtime-dom 就是连接 runtime-core 与浏览器平台的桥梁。它通过实现 DOM 专属的操作接口(如 createElement、patchProp)传入 createRenderer,构造出浏览器专用渲染器。

换句话说,runtime-core 是发动机,runtime-dom 是轮胎。

2. createRenderer:平台无关的渲染工厂

Vue 使用工厂函数创建渲染器:

const renderer = createRenderer(rendererOptions)

这个 rendererOptionsruntime-dom 提供,包含:

{
createElement,
patchProp,
insert,
remove,
setElementText,
setText,
createText,
createComment,
...
}

这就是 Vue 渲染“平台可插拔”的核心。只要你提供一套符合要求的 rendererOptions,就能实现:

  • 浏览器渲染(runtime-dom)
  • 服务端渲染(runtime-server)
  • 小程序平台(如 uni-app 自定义 runtime)
  • 原生 Canvas 渲染(如 pixi.js 适配器)

3. runtime-dom 的关键模块结构

目录如下:

packages/
└── runtime-dom/
├── src/
│ ├── index.ts
│ ├── patchProp.ts
│ ├── modules/
│ │ ├── attrs.ts
│ │ ├── class.ts
│ │ ├── style.ts
│ │ ├── events.ts
│ │ └── ...(每类 patch 拆分成独立模块)
  • index.ts:调用 createRenderer,导出 rendercreateApp
  • patchProp.ts:统一 patch 接口,封装 DOM 更新逻辑
  • modules/:不同类型的 DOM 属性 patch 模块

4. patchProp.ts:DOM 更新策略中枢

export function patchProp(el, key, prevValue, nextValue) {
if (key === 'class') {
patchClass(el, nextValue)
} else if (key === 'style') {
patchStyle(el, prevValue, nextValue)
} else if (isEvent(key)) {
patchEvent(el, key, prevValue, nextValue)
} else if (shouldSetAsProp(el, key, nextValue)) {
patchDOMProp(el, key, nextValue)
} else {
patchAttr(el, key, nextValue)
}
}

它的作用:

  • 对传入的 prop 类型进行分支处理(多分支优化!)
  • 不同类型的属性交由对应模块处理
  • 隐藏了大量浏览器兼容细节

这是 Vue DOM 渲染性能优化的核心点之一。

5. modules/class.ts:类名绑定优化

export function patchClass(el, value) {
if (value == null) {
el.removeAttribute('class')
} else {
el.className = value
}
}

简洁高效,避免了 DOM.classList 的频繁调用。Vue 在编译阶段就会把所有静态类名静态提升。

6. modules/style.ts:样式差量更新

export function patchStyle(el, prev, next) {
const style = el.style
if (!next) {
el.removeAttribute('style')
} else {
for (const key in next) {
style[key] = next[key]
}
if (prev) {
for (const key in prev) {
if (!next[key]) {
style[key] = ''
}
}
}
}
}

特性:

  • 支持内联样式对象更新
  • 做差量比较,删除旧样式项
  • 兼容 null/undefined 清空

7. modules/events.ts:事件绑定优化

export function patchEvent(el, name, prevVal, nextVal) {
const invokers = el._vei || (el._vei = {})
const existing = invokers[name]

if (nextVal && existing) {
existing.value = nextVal
} else {
const eventName = name.slice(2).toLowerCase()
if (nextVal) {
const invoker = (invokers[name] = createInvoker(nextVal))
el.addEventListener(eventName, invoker)
} else if (existing) {
el.removeEventListener(eventName, existing)
invokers[name] = undefined
}
}
}

特性:

  • 事件函数缓存,避免频繁解绑/重绑
  • 使用 invoker 包装函数动态更新
  • 高性能、高兼容性

8. 自定义平台实现参考

如果你要写一个“Vue for Canvas”:

createRenderer({
createElement: () => new Sprite(),
insert: (child, parent) => parent.addChild(child),
patchProp: (el, key, _, next) => {
el.setAttr(key, next)
},
...
})

这就是 Vue 渲染器系统的力量 —— 只要你能实现 DOM 接口,Vue 就能运行。

9. runtime-dom 还能怎么玩?

  • 自定义 patchProp 扩展 web component 支持
  • 封装第三方库适配层(如对 echarts 封装 DOM 属性)
  • 实现一个 mini 版 runtime-dom 用于教学/调试
  • 和 devtools 对接实现自定义调试工具

10. 总结

runtime-dom 是 Vue 渲染系统的“落地执行者”,它的设计核心在于:

  • DOM 操作职责模块化、类型分支优化
  • runtime-core 解耦,实现渲染平台可插拔
  • 高性能实现 patch/绑定/更新策略
  • 能作为自定义平台渲染器的模板参考

深入理解 runtime-dom,不只是为了看懂源码,更是打开“自定义 Vue 渲染平台”大门的钥匙。

推荐阅读

  • runtime-core createRenderer 源码
  • runtime-dom patchProp 源码
  • 官方说明平台无关架构
  • Vue Custom Renderer 示例
举报

相关推荐

0 条评论