euv 条件渲染与列表渲染
euv 是一个 Rust + WASM 前端 UI 框架,将响应式编程的强大能力带给了 Web 开发。构建动态用户界面最基础的能力之一就是根据条件渲染内容以及遍历集合。在本文中,我们将深入探索 euv 的条件渲染机制——包括 if/else、match 和属性级别的条件表达式——以及 for 循环列表渲染的能力。
目录
if/else 条件渲染
euv 中最简单的条件渲染形式是 if/else 表达式。它允许你根据一个响应式的 Signal<bool> 来切换 UI 片段的显示与隐藏。
以下是一个基础示例:
let show_details: Signal<bool> = use_signal(|| false);
html! {
primary_button { label: "Toggle" onclick: use_toggle(show_details) "Toggle" }
if { show_details.get() } { div { "Details visible" } } else { "" }
}
在这个示例中,我们创建了一个布尔信号 show_details,初始值为 false。use_toggle 工具函数被绑定到按钮的 onclick 事件上,每次点击按钮时都会翻转信号的值。当 show_details 为 true 时,显示包含 "Details visible" 文本的 div;否则渲染空字符串 ""。
重要提示: euv 的 if 表达式中 else 分支是强制性的,不能省略。当需要不渲染任何内容时,使用空字符串 "" 作为 else 分支的内容。
这种模式非常适合简单的显示/隐藏切换,比如展开/折叠区域、显示模态对话框或展示加载指示器。
match 条件渲染
当你需要在两个以上的分支之间做出选择时,euv 的 match 表达式提供了一种干净且穷举的方式来处理多种条件。match 表达式会求值并将渲染路由到对应的分支。
let user_type: Signal<String> = use_signal(|| "guest".to_string());
html! {
match { user_type.get().as_str() } {
"guest" => { div { "Welcome, guest!" } }
"user" => { div { "Hello, user!" } }
_ => { div { "Welcome, administrator!" } }
}
}
在这个示例中,match 表达式检查 user_type 的值,并根据用户是 "guest"、"user" 还是管理员(通配符 _ 分支)来渲染不同的欢迎消息。
重要提示: euv 中的每个 match 表达式都必须包含一个通配符 _ 分支。这确保了模式匹配的穷举性——如果你忘记处理某个情况,编译器会发出警告。通配符分支充当默认的回退方案。
match 表达式非常适合基于角色的 UI、多步骤向导、状态机,或任何需要根据单个响应式值渲染不同内容的场景。
属性值条件渲染
有时你不想条件渲染整个元素,而是想条件地设置其属性——比如 CSS 类名或内联样式。euv 支持在属性值中直接使用条件表达式。
let is_active: Signal<bool> = use_signal(|| false);
html! {
div {
class: if { is_active.get() } { c_active() } else { c_inactive() }
style: {
color: if { is_active.get() } { "#4f46e5".to_string() } else { "inherit".to_string() };
border_bottom: if { is_active.get() } { "2px solid #4f46e5".to_string() } else { "2px solid transparent".to_string() };
}
"Tab item"
}
}
在这里,class 属性根据 is_active 信号被条件地设置为 c_active() 或 c_inactive()。类似地,style 块中包含 color 和 border_bottom 的条件值。当 is_active 为 true 时,元素获得靛蓝色和下边框;当为 false 时,继承默认颜色并获得透明边框。
这种模式对于设置交互元素(如标签页、按钮、导航项或任何外观应随状态变化的组件)的样式非常有用。
构建 Tab 切换器
将属性值条件渲染与 match 渲染相结合,我们可以构建一个完整的 Tab 切换器组件。这是 Web 应用中最常见的 UI 模式之一。
let tab: Signal<String> = use_signal(|| "info".to_string());
html! {
div {
div {
class: c_tab_bar()
div {
class: if { tab.get() == "info" } { c_tab_item_active() } else { c_tab_item_inactive() }
onclick: move |_event: Event| { tab.set("info".to_string()); }
"Info"
}
div {
class: if { tab.get() == "settings" } { c_tab_item_active() } else { c_tab_item_inactive() }
onclick: move |_event: Event| { tab.set("settings".to_string()); }
"Settings"
}
}
match { tab.get().as_str() } {
"info" => { div { "Information content" } }
_ => { div { "Settings content" } }
}
}
}
让我们来分解这段代码:
- Tab 栏: 外层使用
c_tab_bar()类的div作为标签栏容器。 - Tab 项: 每个标签项是一个
div,其类名根据是否与当前tab信号值匹配来条件设置。onclick处理器在点击时更新tab信号。 - Tab 内容:
match表达式根据当前标签渲染对应的内容。当tab为"info"时显示 "Information content";否则(_通配符)显示 "Settings content"。
这个模式扩展性很好——你可以通过添加更多标签项 div 和对应的 match 分支来增加更多标签页。响应式系统确保只有活动标签的内容会被渲染,当信号变化时 UI 会自动更新。
for 循环列表渲染
当你需要渲染一组数据时,euv 在 html! 宏中提供了 for 循环语法。这允许你遍历一个响应式的 Signal<Vec<T>> 并为每个元素生成渲染内容。
基础列表渲染
let items: Signal<Vec<String>> = use_signal(|| vec!["Learn Rust".to_string(), "Build UI".to_string()]);
html! {
ul {
for item in { items.get() } { li { item } }
}
}
在这个示例中,我们有一个持有字符串向量的信号。for 循环遍历该向量,在 ul 中的每个 li 元素内渲染每个字符串。当 items 信号发生变化(例如添加或删除项目)时,列表会自动重新渲染。
带索引的列表渲染
有时你需要在显示每个项目内容的同时显示其索引。euv 支持在 for 循环中使用解构来同时访问索引和值:
let items: Signal<Vec<String>> = use_signal(|| vec!["Learn Rust".to_string(), "Build UI".to_string()]);
html! {
ul {
for (index, item) in { items.get().iter().enumerate() } {
li { span { index } span { item } }
}
}
}
在这里,iter().enumerate() 为每个元素提供了 index(usize 类型)和 item(&String 类型)。索引渲染在一个 span 中,项目文本渲染在另一个 span 中,实现了带编号的列表效果。
这个模式对于渲染动态数据(如搜索结果、待办事项列表、产品目录或任何可能在运行时变化的集合)至关重要。
最佳实践与常见模式
以下是在 euv 中使用条件渲染和列表的一些建议:
- 始终包含
else分支: euv 要求必须包含。对于空内容使用""。 - 始终在
match中包含_通配符: 这确保了穷举匹配,防止运行时错误。 - 多分支时使用
match: 当有两个以上的条件时,match比嵌套的if/else更清晰。 - 将条件逻辑放在信号中: 将复杂条件移到计算信号中,保持 `html! 宏的简洁和可读性。
- 善用条件属性: 与其条件渲染两个独立的元素,不如考虑在单个元素上使用条件
class或style值。 - 动态列表使用
for循环: 当渲染来自Signal<Vec<T>>的数据时,for循环是惯用方式。当底层数据变化时,它会自动重新渲染。
结论
euv 为条件渲染和列表迭代提供了一套强大且直观的工具集。if/else 表达式处理简单的切换,match 处理多分支逻辑,条件属性值实现动态样式,for 循环轻松渲染集合。通过组合这些模式,你可以用简洁、声明式的代码构建丰富的交互式用户界面。
在下一篇文章中,我们将探索 euv 中的事件处理——如何响应用户交互、处理表单输入,以及利用全面的浏览器事件支持。