我抛弃了 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 作品。

扩展阅读

相关推荐
李明卫杭州1 小时前
Vue2 vs Vue3 的 h 函数:渲染函数完整迁移指南
前端
星栈1 小时前
LiveView 的认证系统:从登录到权限,我一开始以为有 `current_user` 就算完事了
前端·前端框架·elixir
在因斯坦1 小时前
摸摸鱼之前端自己研究 Jenkins 自动化部署
前端
snpgroupcn2 小时前
SAP实施风险管控注意事项:四大风险域与防范策略
前端·数据库·人工智能
阿成学长_Cain2 小时前
Linux talk 命令详解:经典终端实时聊天工具,无需图形界面即可对话
linux·运维·前端
lichenyang4532 小时前
从零开始写 HarmonyOS Web 容器:先让 ArkWeb 加载本地 H5
前端
kyriewen3 小时前
一个看不见的撇号,让Claude Code追踪了中国开发者三个月
前端·ai编程·claude
莫生灬灬3 小时前
DY联系人聊天Web面板支持获取联系人/聊天记录/发送消息
前端·chrome·websocket·c#
郑州光合科技余经理3 小时前
海外外卖平台源码改造实战——多语言核心代码实现
java·开发语言·前端·后端·mysql·架构·php