我抛弃了 DOM,但保留了无障碍访问

VectoJS 是一个基于 Canvas 原生构建的 UI 运行时,具备虚拟数学树(Virtual Math Tree)、语义化无障碍映射、WebGL/WebGPU 后端以及支持智能体(Agent)驱动的控件。

过去十年的每一个 UI 框架都做出了不同的押注:DOM 是底层基底 (substrate),而框架的任务是以更快的速度管理它,或者用更好的语法将其封装起来。React 使用虚拟 Diff 来管理它。Svelte 通过编译消除了管理它的 Runtime 开销。Tailwind 减轻了为其编写样式的痛苦。但它们依然都假设:UI 的底层结构是一棵 HTML 元素树。

VectoJS 打破了这一假设。它将所有内容------文本、按钮、可滚动列表,甚至数以千计的实时数据点------全部渲染到一个 <canvas> 元素上。底层没有任何 HTML 树。一个 Button 只是一个普通的 TypeScript 对象,包含位置 (position)、尺寸 (size) 以及一个 render() 方法;整个 UI 是由这些对象构成的保留模式场景图 (retained scene graph),像游戏引擎的场景一样在每一帧进行遍历和绘制,而不是像文档那样进行流式布局 (layout)。

typescript 复制代码
class DangerButton extends Button {
  override render(r: IRenderer): void {
    r.beginPath();
    r.roundRect(0, 0, this.width, this.height, 8);
    r.fill('#dc2626');
    super.render(r); // 在顶层绘制文本标签
  }
}

没有 CSS 优先级 (specificity),没有层叠 (cascade),也没有因为写完样式后又去读取而导致的布局抖动 (layout thrashing)------对象自身的字段 (fields) 就是唯一存在的状态。继承和组合的运作方式与任何其他 TypeScript 代码库完全一致,因为这就是纯粹的 TypeScript,而不是伪装成代码的模板语言。

显而易见的质疑

如果你读到了这里,你可能会想:好吧,但这不过是重新发明了 <canvas> 游戏而已,而且 Canvas 一直是无障碍访问 (accessibility) 的黑洞。屏幕阅读器只能看到一个不透明的位图,Ctrl+F 也搜不到任何东西。对于在此之前出现的所有 Canvas 应用来说确实如此,这也是大多数团队不考虑将 Canvas 用于真正 UI 开发的实际原因。

为了填补这一空白,我们具体构建了这样一套机制:每一个具有交互性 (interactive) 的实体,都会在一个精确定位于 Canvas 上方的图层中,映射出一个不可见的、真实的 DOM 节点------比如一个 <button>、一个 <input> 或一个 <a> 标签。这个节点的 Transform 属性在每一帧都会重新同步。因此,如果实体移动、缩放或旋转,这个不可见的 DOM 节点也会随之移动。键盘焦点、原生指针事件 (pointer events) 以及屏幕阅读器都会直接作用于这个真实的元素上,因为它确实是一个真实的 DOM 节点------只不过它是透明的,完美地覆盖在绘制内容之上。

这并不是没有代价的,我们也不打算粉饰太平:每一个交互实体对应一个真实的 DOM 节点,并且需要在每一帧保持同步,这就是它的开销。对于按钮、链接和表单控件------这些用户实际需要接触的元素------付出这样的开销是合理的。这也正是为什么我们不对典型 VectoJS 场景中另外 99% 的元素设置映射的原因:独立的粒子、字形 (glyphs) 以及数据点,除了一个 Draw Call 之外,不会产生任何额外开销,因为它们根本不需要交互。

这种分离带来了什么

因为非交互路径是零成本的,VectoJS 真正擅长处理的工作负载,正是那些会让基于 DOM 的 UI 彻底崩溃的场景:一个包含数百个可拖拽、相互连接的节点以及实时贝塞尔曲线的完整节点图编辑器,以 60fps 的帧率重绘,而图表本身零 DOM 元素;一个通过 WebGPU 计算通道驱动数万个粒子运动的场景,并在不支持 WebGPU 时无缝回退到 CPU 处理;一个能根据鼠标指针实时重排整本书籍的文本阅读器,对于这种规模的流式布局操作,没有任何现代浏览器引擎是为了如此流畅地执行它而构建的。

体验节点编辑器 · 体验粒子力场 · 体验重排阅读器

我们不会向你提供一个单一的"快 N 倍"的数字,因为根本没有绝对的标准------这取决于你的场景中有多少比例是真正可交互的,以及你的 GPU 和浏览器性能。我们能提供的是在 Demo 中内置实时的 FPS / 实体数量读数,以便你可以用自己的硬件进行客观测量,而不是盲目相信我们的数据。

亲自体验

这里的所有内容都在 GitHub 上以 MIT 许可证开源:包括引擎 (engine)、你可能正在阅读的文档网站 (docs site),以及一个社区画廊 (gallery)------任何人都可以在画廊中通过单文件 Pull Request 提交自己的 VectoJS 作品。

扩展阅读

相关推荐
东方小月6 小时前
从零开发一个 Coding Agent(四):使用状态机校验大模型事件流
前端·人工智能·后端
Csvn6 小时前
🧩 ESM vs CJS 混用的 7 个「天坑」——从 TypeScript 编译到 Node 与浏览器
前端
Csvn6 小时前
🎯 Web 性能 API 集合:Performance Observer 的 5 个冷门妙用
前端
Csvn6 小时前
深入 React 闭包陷阱:从根源上理解并根治 stale closure
前端
whyfail7 小时前
前端学 Spring Boot(8):接口为什么越用越慢?
前端·spring boot·后端
用户059540174467 小时前
LangChain 记忆测试踩坑实录:这两个坑让我排查了 4 小时
前端·css
程序员黑豆7 小时前
鸿蒙应用开发:@Monitor 装饰器使用教程
前端·harmonyos
SamChan908 小时前
在Web应用中集成PDF多语言翻译功能:PDFTranslator API实战指南
前端·python·ai·pdf·yapi·机器翻译
kyriewen8 小时前
AI Agent 9秒删光了生产数据库——我给自己的项目做了5个紧急检查
前端·ai编程·claude
IT_陈寒9 小时前
JavaScript的this又双叒叕让我怀疑人生了
前端·人工智能·后端