渲染器
渲染虚拟 DOM
Renderer 是框架内部的渲染器类型(pub(crate)),负责将虚拟 DOM 渲染到真实 DOM。通常不需要手动创建,使用 mount 即可自动管理渲染器:
use euv::*;
// mount 内部自动创建 Renderer 并渲染
mount("#app", app);提示
Renderer 是 pub(crate) 类型,无法在 euv crate 外部直接使用。使用 mount 函数即可自动管理渲染器的创建和渲染。
渲染模式
Renderer 内部提供两种渲染模式,框架根据场景自动选择:
增量渲染(render)
增量 Diff 算法,对比新旧虚拟 DOM 树并仅更新变化的部分:
- 标签相同 → 仅修补属性和子节点
- 标签不同 → 替换整个 DOM 节点
- 文本内容相同 → 跳过更新
完全替换渲染(render_full_replace)
跳过 Diff,直接替换所有子节点。框架在 match 分支切换(如路由变化)时自动使用此模式,避免增量 Diff 在不相关的分支间错误对齐节点。
提示
这两种渲染模式由框架内部自动选择,用户无需手动调用。Renderer 是 pub(crate) 类型,无法在 euv crate 外部直接使用。
Keyed Diffing
渲染器支持基于 key 的列表 Diff 算法,当所有子节点都带有 key 属性时自动启用:
html! {
ul {
for item in {items.get()} {
li {
key: item.id
item.name
}
}
}
}Keyed Diffing 的优势:
- 列表重排序时,通过
key映射复用已有 DOM 节点,避免不必要的删除和重建 - 插入/删除元素时,仅操作受影响的节点
提示
当所有子节点都带有 key 属性时,框架自动使用 Keyed Diffing。如果部分或全部子节点没有 key,则回退到位置 Diffing(按索引逐一比较)。
布尔属性
对于 checked、disabled、selected、readonly 等布尔属性,框架使用 DOM 属性(property)而非 HTML 属性(attribute):
html! {
input {
r#type: "checkbox"
checked: agree_signal
}
input {
r#type: "text"
disabled: disabled_signal
}
}注意
布尔属性必须通过 Signal<bool> 传入,不能直接传字符串 "true" / "false"。
渲染优化:视觉等值跳过
框架在 DynamicNode 重新渲染时,会通过 visual_eq 比较新旧虚拟 DOM 树的视觉输出。如果渲染结果完全相同,则跳过 DOM 修补操作,避免不必要的 DOM 操作:
- 信号变化触发
DynamicNode重新渲染 - 渲染闭包执行后,框架比较新旧虚拟 DOM 树
- 如果视觉等值(标签、属性、子节点均相同),跳过修补
match分支切换时不受此优化影响,始终执行完全替换
提示
这一优化对频繁信号更新但 UI 实际未变的场景(如定时器信号更新但渲染结果不变)特别有效,减少了大量不必要的 DOM 操作。
DOM 清理机制
框架在移除 DOM 节点时,会自动递归清理关联的框架资源:
- 事件处理器 — 通过
data-euv-id属性查找并移除全局注册表中的事件处理器 - 动态节点监听器 — 通过
data-euv-dynamic-id属性移除动态节点的重新渲染回调 - 信号监听器 — 通过
data-euv-signal-addrs属性清除关联的信号订阅,并将信号标记为不活跃 - 文本节点信号 — 清理绑定到文本节点的信号监听器
提示
DOM 清理由框架自动管理,在 render_full_replace、节点替换等操作时自动执行,无需手动干预。