vue自定义渲染器是将vnode映射为目标平台操作的“翻译官”,不涉及响应式与编译,仅通过实现createelement、patchprop、insert、remove、setelementtext等核心方法,使vue组件可在canvas、小程序等非dom环境运行。

Vue 渲染器处理自定义节点,核心在于把 VNode 映射成目标平台可执行的操作,而不是修改组件写法。它不碰响应式系统、也不改模板编译逻辑,只接管“怎么创建、更新、插入、删除节点”这一层。
自定义节点的本质是平台适配
Vue 的虚拟节点(VNode)本身是纯 JS 对象,描述结构、属性和子节点,与 DOM 无关。比如:
{ type: 'rect', props: { x: 10, y: 20, width: 100, color: '#ff6b6b' }, children: [] }
这个对象在浏览器里不会自动变成 <div>,在 Canvas 里也不会自动画矩形——需要你用 <code>createRenderer 提供的接口告诉 Vue:“遇到 rect 类型,就调用 ctx.fillRect()”。
关键不是“定义新标签”,而是为每种自定义类型提供对应的底层操作。
必须实现的核心方法
要让自定义节点跑起来,RendererOptions 至少要覆盖以下方法:
-
createElement(type):根据type(如'rect'、'text'、'node-vue-shape')返回一个平台节点对象(可以是 Canvas 绘图指令封装、小程序 setData 数据结构、或轻量级 JS 节点树) -
patchProp(el, key, prev, next):更新属性。例如color改变时重设ctx.fillStyle;x变化时缓存新坐标用于下次重绘 -
insert(child, parent, anchor?):把子节点挂到父容器。Canvas 中可能是收集绘制顺序;终端渲染中可能是推入数组 -
remove(el, parent):从父容器移除该节点(如从 Canvas 绘制队列中剔除) -
setElementText(el, text):设置文本内容(Canvas 中调用fillText,终端中拼接字符串)
注意:
type字符串由组件模板或h()函数传入,比如<rect :x="10" :color="'blue'"></rect>最终生成的 VNode 的type是'Rect'或'rect',取决于你注册时怎么写的。
实际场景中的常见做法
Canvas 渲染器
createElement('rect')返回{ type: 'rect', props: {}, draw(ctx) { ctx.fillRect(...) } };insert不操作真实 DOM,而是把该对象加入待绘制列表;patchProp更新后标记为“需重绘”。图编辑器(如 X6/G6)集成 Vue 节点
不自己写完整渲染器,而是借助@antv/x6-vue-shape这类封装库。它内部已实现vue-shape类型的createElement和insert,你只需把 Vue 组件传给component属性,X6 负责挂载、更新、销毁。小程序环境
createElement返回一个模拟节点对象;patchProp把属性转成setData的字段路径;insert触发this.$scope.setData()更新视图树。命令行/终端输出
createElement('box')返回{ type: 'box', props: {}, toString() { return '┌──┐\n│ │\n└──┘' } };renderToConsole(rootNode)递归调用toString()拼接输出。
如何让组件识别你的自定义节点
不需要全局注册标签。只要你在 h() 或模板中使用了某个 type 字符串,且 createElement 方法能识别它并返回合法节点对象,Vue 就会调用对应逻辑。
例如:
// 在 setup 中
import { h } from 'vue'
export default {
setup() {
return () => h('rect', { x: 50, y: 30, color: 'red', width: 80, height: 40 })
}
}
只要你的渲染器 createElement 碰到 'rect' 就返回可绘制对象,这个组件就能在 Canvas 中渲染出来。
不复杂但容易忽略










