html! 宏
2026/5/15大约 2 分钟euvuirustwasmmacroshtml
基本用法
use euv::*;
html! {
div {
class: c_container()
h1 { "Hello, euv!" }
button {
onclick: move |_| { /* handle click */ }
"Click me"
}
}
}字符串属性
html! {
input {
r#type: "text"
placeholder: "Enter your name"
value: "default value"
}
}提示
Rust 关键字(如 type)需使用 r# 前缀:r#type: "text"
信号属性
let count: Signal<i32> = use_signal(|| 0);
html! {
span { count }
}事件属性
html! {
button {
onclick: move |event: NativeEvent| {
// 处理点击
}
"Click me"
}
}CSS 类属性
html! {
div {
class: c_container()
"Content"
}
}内联样式属性
支持两种语法——对象语法和表达式语法:
对象语法
html! {
div {
style: {display: "flex"; padding: "10px"; font_size: "14px";}
"Content"
}
}动态样式值
样式属性值支持花括号包裹的动态表达式:
html! {
div {
style: {background: {color};}
"Dynamic background"
}
}提示
内联样式使用 snake_case,自动转换为 kebab-case(如 font_size → font-size)。
布尔属性
let agree: Signal<bool> = use_signal(|| true);
html! {
input {
r#type: "checkbox"
checked: agree
}
}自定义属性
html! {
div {
data_role: "container"
data_id: "12345"
aria_label: "Demo section"
"Custom attributes"
}
}提示
data_* 和 aria_* 属性自动转换为 data-* 和 aria-* 格式。使用 r# 前缀处理 Rust 保留字。
条件渲染
if/else
html! {
if {show.get()} {
div { "Visible" }
} else {
""
}
}else if 链
html! {
if {score.get() >= 90} {
div { "Excellent" }
} else if {score.get() >= 60} {
div { "Pass" }
} else {
div { "Fail" }
}
}match 表达式
html! {
match {route.get().as_str()} {
"/" => { page_home() }
"/about" => { page_about() }
_ => { page_not_found() }
}
}注意
if 的 else 分支不能省略,match 必须包含 _ 通配分支。
属性值条件渲染
if 条件渲染不仅可用于子节点位置,还可在属性值中使用,实现响应式的属性切换:
let is_active: Signal<bool> = use_signal(|| false);
html! {
div {
class: if { is_active.get() } { c_active() } else { c_inactive() }
"Content"
}
}样式中同样支持条件渲染:
html! {
div {
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"
}
}提示
属性值中的 if 条件会自动包装为响应式 Signal<String>,信号变化时属性值自动更新,无需手动订阅。
列表渲染(for 循环)
html! 宏支持 for 循环语法来渲染动态列表:
let items: Signal<Vec<String>> = use_signal(|| vec!["Rust".to_string(), "euv".to_string()]);
html! {
ul {
for item in {items.get()} {
li { item }
}
}
}带索引的循环:
html! {
ul {
for (index, item) in {items.get().iter().enumerate()} {
li { item }
}
}
}提示
for 循环中的迭代表达式需用花括号 {} 包裹。每次信号变化时,循环体会自动重新求值。
嵌入表达式
动态表达式(响应式)
使用花括号 {expr} 包裹的表达式会自动包装为 DynamicNode,信号变化时自动重新渲染:
html! {
div {
{format!("Count: {}", count.get())}
}
}静态表达式
裸标识符(无花括号)通过 IntoNode 进行静态一次性转换,不会响应信号变化:
html! {
div {
count
}
}