Rust in Everything
基于 dioxus 0.7.10

浏览器渲染

这一部分讲 VirtualDom 和真实浏览器之间的那一层。源码在 packages/web/src(lib.rs 的主循环、dom.rs、mutations.rs、events/、document.rs)、packages/interpreter/src(unified_bindings.rs 交给 sledgehammer 生成批量绑定,ts/core.ts 是 JS 侧的基类)和 packages/document/src(Document trait、Title 等组件、eval)。VirtualDom 内核 产出的是一串 WriteMutations 调用、收的是 handle_event;这里讲浏览器那一侧怎么把它们接上 DOM。

  1. WebsysDom 与 interpreter:dioxus_web::launch 把一个永不结束的 future 交给 spawn_local,循环里 select! 等 wait_for_work 和流式水合消息,醒来就 render_immediate + flush_edits;WebsysDom 把指令编码进 sledgehammer 的缓冲,一次 run() 让 JS 解码执行,模板第一次用时建 DOM、以后 cloneNode。实测一次 SetText 跨边界 21 字节,加 100 行也只调一次 run()。
  2. 事件委托:冒泡事件在根元素上每种只挂一个监听器,不冒泡的挂在元素上;wasm 闭包从目标往上找 data-dioxus-id,把 web_sys 事件包成 PlatformEventData,用户要 MouseData 时再转换;prevent_default 只认同步部分,stop_propagation 管不到浏览器自己的传播;0.7.10 里移除监听器的两个问题。
  3. document 与 eval:Title、Meta、Link、Script、Style 在浏览器上用 effect 直接改 <head>,在服务端由 ServerDocument 收集、render_head 输出,水合时靠水合数据里的一个 bool 不重复插入;eval 的 dioxus.send / recv 通道,以及在服务端调用得到的 Err(Finished)。
flowchart TB
  vdom["VirtualDom"] -->|WriteMutations| websys["WebsysDom"]
  websys -->|"一次 run()"| interp["JS interpreter"]
  interp --> dom["DOM"]
  dom -->|事件冒泡到根| handler["wasm 事件闭包"]
  handler -->|handle_event| vdom
  vdom --> headc["Title Meta 等组件"]
  headc --> docu["Document"]
  docu --> headel["head 和 eval"]

前两页是更新主线在浏览器里的两端:事件从 DOM 进来、指令回到 DOM。第三页靠近首屏主线,它的服务端一半在 render_head 里,客户端一半在水合里。水合本身(rehydrate 怎么认领服务端送来的节点)在 水合。

💬 关联讨论

发起讨论
加载中...