X6 进阶指南:使用 Shape.HTML 渲染与更新 HTML 节点(原理与实战)
【免费下载链接】X6🚀 JavaScript diagramming library that uses SVG and HTML for rendering.项目地址: https://gitcode.com/GitHub_Trending/x6/X6
本指南基于 X6 内置的Shape.HTML能力,系统讲解如何用 HTML 渲染节点内容、如何通过effect机制响应节点属性变化并自动更新节点 DOM。读完本文,你将掌握 HTML 节点的注册、三种内容形态、默认 DOM 结构与更新触发原理,并能复现悬浮动画与定时刷新两类实战案例。
为什么需要 HTML 节点
X6 是一个使用 SVG 与 HTML 进行渲染的 JavaScript 图编辑库。常规节点基于 SVG 绘制,但对交互复杂、样式多变的内容(如富文本、图表、输入框、悬浮动画)而言,SVG 实现成本很高。X6 在Shape命名空间下内置了HTML节点类型,把节点内容直接交给浏览器 DOM 渲染,从而获得 HTML/CSS 的全部表达能力。
从源码看,HTML节点本身是Node的子类(src/shape/html.ts),并在Node.registry中以html为键注册;真正负责渲染 DOM 的视图html-view也被注册到NodeView.registry(src/shape/html.ts)。也就是说,使用HTML节点不需要额外引入插件或依赖,开箱即用。
快速开始:注册并渲染 HTML 节点
注册一个 HTML 节点只需要调用Shape.HTML.register,并为其提供唯一的shape名称和一个返回 DOM 的html方法:
import { Shape } from '@antv/x6' Shape.HTML.register({ shape: 'custom-html', width: 160, height: 80, html() { const div = document.createElement('div') div.className = 'custom-html' return div }, }) graph.addNode({ shape: 'custom-html', x: 60, y: 100, })要点说明:
shape:必填,节点类型标识,addNode时通过shape引用它。源码中若未指定shape,会直接抛出HTML.register should specify 'shape' in config.错误(src/shape/html.ts)。width/height:节点默认尺寸,addNode时可按节点实例覆盖。html:节点内容的生产函数,返回一个HTMLElement。- 注册本质上是在调用
Graph.registerNode(shape, { inherit: 'html', ...others }, true)(src/shape/html.ts),测试用例 html.spec.ts 对这条注册链路做了完整断言。
html 字段的三种形态
html字段在源码中被定义为HTMLComponent联合类型(src/shape/html.ts):
type HTMLComponent = | string // HTML 字符串 | HTMLElement // 现成的 DOM 元素 | ((cell: Cell) => HTMLElement | string) // 函数,接收节点 cell视图在渲染时按类型分支处理(src/shape/html.ts):
- 字符串:直接写入容器的
innerHTML; - HTMLElement:通过
Dom.append追加进容器; - 函数:先以当前节点 cell 为参数调用,再按返回值(字符串或元素)处理。
因此你可以这样注册一个最简节点:
Shape.HTML.register({ shape: 'static-html', html: '<div style="padding:8px">Hello X6</div>', })对应的字符串、元素、函数三种形态,以及空字符串、函数返回 null、缺少容器等边界情况,在测试 html.spec.ts 中都有覆盖验证。
HTML 节点的默认 DOM 结构
HTML类通过HTML.config声明了默认 markup 与 attrs(src/shape/html.ts),节点内部结构如下:
rect(selector:body):铺满节点的透明底板,fill: 'none'、stroke: 'none'、refWidth/refHeight: '100%';foreignObject(selector:fo):承载 HTML 内容的外来对象容器,同样refWidth/refHeight: '100%';text(selector:label):节点标签文本层。
foreignObject的完整子结构由Markup.getForeignObjectMarkup()生成(src/view/markup.ts):foreignObject(fo) → body(foBody,xhtml 命名空间) → div(foContent),其中foContent才是html方法返回内容真正挂载的容器。视图渲染时会清空foContent再写入新内容(Dom.empty(container)),避免旧内容残留。
理解了这套结构,你就知道:HTML 节点仍是可选中、可拖动、可连线的正常节点,只是节点视觉主体由 DOM 呈现。
更新节点内容:effect 机制
注册节点时提供effect字段——它是当前节点的prop数组。当其中任一 prop 变化时,html方法会重新执行并返回新 DOM,从而更新节点内容:
Shape.HTML.register({ shape: 'custom-html', width: 160, height: 80, effect: ['data'], html(cell) { const { color } = cell.getData() const div = document.createElement('div') div.className = 'custom-html' div.style.background = color return div }, })这里的html(cell)可以读取节点数据(如cell.getData())来动态生成内容。
底层原理:HTML 节点的视图在初始化时监听节点的change:*事件(src/shape/html.ts)。任意 prop 变化时,处理器会取该节点注册时保存的effect列表:
- 若
effect存在且包含当前变化的 key,则调用renderHTMLComponent()重渲染; - 若
effect存在但不包含该 key,则不重渲染; - 若未设置
effect,则任何 prop 变化都会触发重渲染。
测试 html.spec.ts 精确验证了这一行为:effect: ['size']时,resize()会触发重渲染、setPosition()不会;不设effect时setPosition()也会触发重渲染。
因此,当节点内容只依赖data时,把effect收敛为['data'],可以避免因位置、尺寸等变化引发的无意义 DOM 重建,是控制重渲染开销的实用手段。
实战一:CSS 悬浮动画
完整示例见 site/src/tutorial/intermediate/html/basic/index.tsx 与配套样式 index.less。
示例注册了custom-html节点并在图中添加一个实例,配合graph.centerContent()居中显示。节点内容只是一个div,其翻转动画完全用 CSS 实现:.custom-html::before默认rotateX(180deg)隐藏,:hover::before时rotateX(0)展开,并带transition: 0.7s ease-in-out transform。这类效果若用 SVG 实现需要复杂的路径与滤镜,而 HTML 节点只需几行 CSS——这正是 HTML 节点的典型优势场景。
实战二:定时刷新节点内容
完整示例见 site/src/tutorial/intermediate/html/update/index.tsx。
示例注册custom-update-html,html(cell)从cell.getData().color读取颜色并写入背景样式;添加节点时通过data: { color: '#333232' }初始化数据,随后用setInterval每 2 秒调用node.setData({ color: Color.randomHex() })(Color同样从@antv/x6导出)。
由于注册时声明了effect: ['data'],每次setData改变dataprop 都会触发html(cell)重新执行,节点背景色随之更新。这条「数据驱动 → effect 匹配 → DOM 重建」的链路,与上一节的原理部分完全对应。
常见边界与注意事项
结合源码与测试,使用 HTML 节点时还需留意:
- 内容为空:
html返回空字符串或函数返回 null 时,容器内容保持为空,不会报错(html.spec.ts); - 容器缺失:视图未就绪时
foContent可能不存在,渲染逻辑会静默跳过(html.spec.ts); - 重渲染前清空:每次渲染前容器都会被
Dom.empty,因此不要在html返回的元素上挂接需要持久化的状态,跨渲染的状态应放在节点data中; - 事件监听释放:视图销毁时会解除
change:*监听(src/shape/html.ts),避免内存泄漏。
延伸阅读
- HTML 节点中文文档
- 核心实现:src/shape/html.ts
- 默认 markup 生成:src/view/markup.ts
- 行为验证:tests/shape/html.spec.ts
- 若需更进一步,可结合 X6 教程中关于节点与节点样式的内容,将 HTML 节点与普通 SVG 节点在同一图中混合使用。
【免费下载链接】X6🚀 JavaScript diagramming library that uses SVG and HTML for rendering.项目地址: https://gitcode.com/GitHub_Trending/x6/X6
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考