浏览器渲染
这一部分讲 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。
- 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()。 - 事件委托:冒泡事件在根元素上每种只挂一个监听器,不冒泡的挂在元素上;wasm 闭包从目标往上找
data-dioxus-id,把web_sys事件包成PlatformEventData,用户要MouseData时再转换;prevent_default只认同步部分,stop_propagation管不到浏览器自己的传播;0.7.10 里移除监听器的两个问题。 - 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 怎么认领服务端送来的节点)在 水合。
💬 关联讨论
发起讨论加载中...