一款声明式 Rust WebAssembly UI 框架 - Euv(哎呦喂)
·
一款声明式 Rust WebAssembly UI 框架 - Euv(哎呦喂)
项目概述
Euv 是一个基于 Rust 语言开发的声明式、跨平台 UI 框架,构建在 WebAssembly 之上,融合了虚拟 DOM、响应式 Signal 系统以及类 HTML 宏语法,为开发者提供现代、高效且符合人体工程学的前端开发体验。
核心特性
- 声明式 UI:通过
html!宏编写类 JSX 语法,编译期类型检查,零运行时开销 - 响应式 Signal:
use_signalHook 驱动的细粒度响应式系统,数据变更自动更新 DOM - 高性能虚拟 DOM:Keyed Diff 算法 + 增量 Patch,最小化 DOM 操作
- 全局事件委托:基于事件冒泡的统一委托机制,减少事件监听器数量,降低内存占用
- CSS-in-Rust:
class!宏 +css_vars!宏,类型安全的样式定义,支持伪类、媒体查询 - 组件系统:
#[component]属性宏标注,Props 自动提取,组件组合零摩擦 - CLI 工具链:内置
euv-cli,支持开发服务器、热更新、一键构建发布
架构设计亮点
Monorepo 架构
| Crate | 职责 | 说明 |
|---|---|---|
| euv-core | 核心运行时 | 虚拟 DOM、响应式系统、渲染器、事件系统 |
| euv-macros | 过程宏 | html!、class!、css_vars!、watch!、var!、#[component] |
| euv-cli | CLI 工具 | dev/build/fmt 三种模式,热更新、wasm-pack 集成 |
| euv | 统一入口 | 聚合 core + macros,对外提供完整 API |
响应式系统架构
Signal (use_signal)
│
├── .get() → 读取当前值
├── .set() → 更新值 + 通知监听器 + 调度 DOM 更新
├── .subscribe() / .replace_subscribe() → 注册变更回调
│
└── schedule_signal_update()
│
└── queueMicrotask → dispatch EuvSignalUpdate Event
│
└── DynamicNode 重新渲染 → 增量 Patch DOM
核心优化:
- Microtask 批处理:多次
signal.set()在同一微任务中自动合并,仅触发一次 DOM 更新 batch_updatesAPI:手动批量更新,抑制中间调度,适合复杂状态变更场景set_silent静默更新:仅触发监听器但不调度 DOM 更新,用于属性信号内部同步skip_equal优化:DynamicNode重新渲染前进行visual_eq比较,无视觉变化则跳过 Patch
虚拟 DOM Diff 算法
| 算法 | 适用场景 | 复杂度 |
|---|---|---|
| Keyed Diff | 所有子节点均带 key 属性 |
O(N) 建映射 + 最小 DOM 移动 |
| Positional Diff | 无 key 或部分子节点缺 key | O(min(M, N)) 逐位比较 |
Keyed Diff 特性:
- 构建
old_key → old_index映射表 - 复用已有 DOM 节点,仅 Patch 属性差异
- 通过
insert_before最小化 DOM 移动操作 - 反向遍历移除废弃节点,避免索引偏移
全局事件委托机制
DOM Element
│
└── data-euv-id="42" (自动分配)
│
└── Event Bubble → window 委托监听器
│
└── HandlerRegistry[(42, "click")] → HandlerSlot → 用户回调
- 支持鼠标、键盘、焦点、表单、拖拽、触摸、滚轮、剪贴板、动画、过渡等 60+ 种事件类型
- 每种事件类型仅注册一个全局监听器,通过
data-euv-id精确路由 - 组件卸载时自动清理事件处理器,杜绝内存泄漏
开发便捷性
1. 声明式 UI 编写
#[component]
fn primary_button(props: VirtualNode) -> VirtualNode {
let PrimaryButtonProps { label, onclick, disabled } = props.into();
html! {
button {
class: if { disabled } { c_primary_button_disabled() } else { c_primary_button() }
onclick: onclick
label
}
}
}
2. 响应式状态管理
fn page_conditional() -> VirtualNode {
let show_details: Signal<bool> = use_signal(|| false);
let user_type: Signal<String> = use_signal(|| "guest".to_string());
html! {
div {
class: c_page_container()
primary_button {
label: "Toggle"
onclick: use_toggle(show_details)
"Toggle"
}
if { show_details.get() } {
div { "Hidden Details" }
} else {
""
}
match { user_type.get().as_str() } {
"guest" => { div { "Welcome, guest!" } }
"user" => { div { "Hello, user!" } }
_ => { div { "Welcome, admin!" } }
}
}
}
}
3. CSS-in-Rust 样式系统
class! {
pub c_card {
background: var!(bg-card);
border-radius: "12px";
padding: "24px";
box-shadow: var!(shadow-card);
media("(max-width: 767px)") {
padding: "16px";
border-radius: "10px";
}
}
pub c_nav_item_inactive {
color: var!(text-nav-item);
hover {
background: "rgba(79, 70, 229, 0.04)";
color: "#4f46e5";
}
}
}
css_vars! {
pub c_theme_light {
bg-primary: "#f8f9fb";
text-primary: "#1a1a2e";
}
}
4. 响应式副作用
let count = use_signal(|| 0_i32);
let name = use_signal(|| String::from("euv"));
watch!(count, name, |count_val, name_val| {
web_sys::console::log_1(
&format!("count={}, name={}", count_val, name_val).into()
);
});
5. CLI 开发工具链
# 开发模式(热更新 + Dev Server)
euv-cli run --crate-path ./example
# 构建发布
euv-cli build --crate-path ./example --release
# 格式化宏代码
euv-cli fmt --path ./src
框架优势
1. 零成本抽象设计
- 编译期宏展开:
html!、class!等宏在编译时生成 Rust 代码,运行时零解析开销 - 类型安全:Props 自动提取、事件类型强校验,编译时消除 UI 逻辑错误
- Signal Copy 语义:
Signal<T>实现Copytrait,仅复制指针地址,Rc引用由全局注册表持有,无 GC 压力
2. 精细 DOM 更新策略
- 属性级 Patch:新旧属性 HashMap 对比,仅更新变化的属性
- 信号绑定属性:
AttributeValue::Signal自动订阅变更,DOM 节点移除时自动清理监听器 - DynamicNode 独立渲染:每个动态节点拥有独立的
Renderer和HookContext,实现局部更新 - arm 切换检测:
match分支切换时自动执行render_full_replace,避免错误复用
3. 完善的生命周期管理
- DOM 子树清理:
cleanup_dom_subtree递归清理事件处理器、动态节点监听器、信号监听器 - Hook 清理:
match分支切换时执行cleanups队列,防止信号泄漏 - Signal 存活标记:
alive标志位确保已清理的 Signal 不再触发无效更新
4. 跨平台响应式布局
use_resizeHook:自动检测视口尺寸,防抖 150ms,桌面/移动端布局自适应切换- CSS 媒体查询:
class!宏原生支持media()语法 - 主题系统:
css_vars!实现明暗主题,一行代码切换
技术栈对比
| 特性 | Euv | Yew | Dioxus | Leptos |
|---|---|---|---|---|
| 虚拟 DOM | ✅ Keyed + Positional Diff | ✅ | ✅ | ❌ (细粒度) |
| 响应式系统 | ✅ Signal + Microtask 批处理 | ❌ (手动更新) | ✅ | ✅ |
| 类 JSX 宏 | ✅ html! |
✅ html! |
✅ rsx! |
✅ view! |
| CSS-in-Rust | ✅ class! + css_vars! |
❌ | ❌ | ❌ |
| 全局事件委托 | ✅ 60+ 事件类型 | ❌ | ❌ | ❌ |
| CLI 工具链 | ✅ dev/build/fmt + 热更新 | ❌ | ✅ | ✅ |
| 组件系统 | ✅ #[component] 宏 |
✅ | ✅ | ✅ |
| 伪类/媒体查询 | ✅ 原生支持 | ❌ | ❌ | ❌ |
| WASM 目标 | ✅ | ✅ | ✅ | ✅ |
| Rust Edition | 2024 | 2021 | 2021 | 2021 |
生态系统与社区
文档与学习资源
- 官方文档:https://docs.ltpp.vip/euv/
- API 文档:https://docs.rs/euv/latest/
- 仓库地址:https://github.com/euv-dev/euv.git
开源协议
- 许可证:MIT License
适用场景
推荐使用场景
- Web 应用前端:需要高性能、类型安全的现代 Web 应用
- 内部管理系统:表单密集、条件渲染复杂的管理后台
- 交互式仪表盘:实时数据更新、响应式布局的数据看板
- 组件库开发:类型安全的 Props、CSS-in-Rust 样式隔离
- WASM 原生应用:追求极致性能的 WebAssembly 应用
核心能力
- 60+ 事件类型覆盖:鼠标、键盘、焦点、表单、拖拽、触摸、剪贴板、动画等
- 内置组件:Button、Card、Modal、Select、FormInput、Textarea、Badge、PageHeader、VConsole
- 示例页面:Signals、Event、List、Conditional、Modal、Select、Async、Form、FileUpload、Timer、Animation、Browser、Lifecycle、Keep-Alive、ComponentBinding、CustomAttrs
总结
Euv 作为一款新兴的 Rust 声明式 UI 框架,在 WebAssembly 生态中独树一帜。通过创新的架构设计——Signal + Microtask 批处理响应式系统、Keyed Diff 虚拟 DOM、全局事件委托机制、CSS-in-Rust 样式系统——为 Rust 前端开发提供了完整且高效的解决方案。
框架的核心优势在于:
- 开发体验:
html!宏 +class!宏 +use_signalHook,三位一体的声明式开发范式 - 运行时性能:Microtask 批处理 + Keyed Diff + 事件委托,多层级优化确保极致渲染效率
- 类型安全:编译期宏展开、Props 自动提取、事件类型强校验,将 UI 错误扼杀在编译阶段
- 工程化支持:CLI 工具链提供 dev/build/fmt 三种模式,内置热更新和代码格式化
对于追求类型安全、高性能和开发效率的 Rust WebAssembly 项目,Euv 是一个值得考虑的优秀选择。随着 Rust 前端生态的不断发展,Euv 有望成为 WebAssembly UI 开发的重要工具。
更多推荐


所有评论(0)