---
title: '條件渲染'
description: '在 html! 中使用 if、if let 和 match 進行條件渲染'
---

import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'

## If 區塊

要有條件地渲染一些標記，我們將其包裝在 `if` 區塊中：

<Tabs>
  <TabItem value="if" label="if">

```rust
use yew::prelude::*;

html! {
    if true {
        <p>{ "True case" }</p>
    }
};
```

  </TabItem>
  <TabItem value="if - else" label="if - else">

```rust
use yew::prelude::*;
let some_condition = true;

html! {
    if some_condition {
        <p>{ "True case" }</p>
    } else {
        <p>{ "False case" }</p>
    }
};
```

  </TabItem>
  <TabItem value="if let" label="if let">

```rust
use yew::prelude::*;
let some_text = Some("text");

html! {
    if let Some(text) = some_text {
        <p>{ text }</p>
    }
};
```

  </TabItem>
  <TabItem value="if let else" label="if let else">

```rust
use yew::prelude::*;
let some_text = Some("text");

html! {
    if let Some(text) = some_text {
        <p>{ text }</p>
    } else {
        <p>{ "False case" }</p>
    }
};
```

  </TabItem>
  <TabItem value="if-let-bindings" label="let 綁定">

大括號主體支援在 html 子節點前使用 `let` 綁定，以及多個子節點：

```rust , ignore
use yew::prelude::*;

html! {
    if condition {
        let label = format!("count: {count}");
        <h2>{"Result"}</h2>
        <span>{label}</span>
    } else {
        "nothing"
    }
};
```

`let` 綁定必須出現在所有 html 子節點之前，不能與它們交錯。

  </TabItem>
</Tabs>

## Match 區塊

`match` 運算式可以直接在 `html!` 中使用，與 `if`/`else` 遵循相同的模式：

<Tabs>
  <TabItem value="match" label="match">

```rust
use yew::prelude::*;

let value: Option<String> = Some("hello".into());

html! {
    match value {
        Some(text) => <p>{text}</p>,
        None => <p>{"Nothing here"}</p>,
    }
};
```

  </TabItem>
  <TabItem value="match-guards" label="if 守衛">

```rust
use yew::prelude::*;

let value: i32 = 42;

html! {
    match value {
        x if x > 10 => <p>{"Big"}</p>,
        x if x > 0 => <p>{"Small"}</p>,
        _ => <p>{"Non-positive"}</p>,
    }
};
```

  </TabItem>
  <TabItem value="match-let" label="let 綁定">

大括號 arm 主體支援 `let` 綁定和多個子節點：

```rust , ignore
use yew::prelude::*;

html! {
    match data {
        Some(item) => {
            let label = format!("Item: {}", item.name);
            let class = if item.important { "highlight" } else { "normal" };
            <p class={class}>{label}</p>
        }
        None => <p>{"No data"}</p>,
    }
};
```

  </TabItem>
</Tabs>

單元素 arm 可以省略大括號。含多個子節點或 `let` 綁定的 arm 需要大括號。

`match` 支援所有標準 Rust 模式，包括 OR 模式（`A | B`）、解構和 `if` 守衛。窮舉性由 Rust 編譯器檢查。

## `if` / `match` 主體內部的迴圈

`if` / `else if` / `else` / `match` 分支主體內部的 `for`、`while`、`loop` 與 `html!` 最外層位置的規則相同，但有一個例外：如果迴圈主體可以被 Rust 完整剖析（內部任何位置都沒有 html 元素），巨集會把這個迴圈視為 Rust 陳述式而不是 html 控制流。

最常見的觸發情形是迴圈主體裡只有一個裸 `{expr}` 區塊：

```rust , ignore
// 可以編譯。for 在最外層，被解析為 html-`for`。
html! {
    for _ in 0..9 {
        {my_foo}
    }
}

// 無法編譯。for 在 `if` 內部，被解析為 Rust 陳述式；
// 之後 rustc 會回報迴圈主體傳回的型別不是 `()`。
html! {
    if condition {
        for _ in 0..9 {
            {my_foo}
        }
    }
}
```

把子節點用 html 元素包起來即可保留 html-`for` 行為：

```rust , ignore
html! {
    if condition {
        for _ in 0..9 {
            <span>{my_foo}</span>
        }
    }
}
```

完整的解決方法集合請參見[清單](./lists.mdx)。
