iT邦幫忙

2025 iThome 鐵人賽

DAY 3
0

聯繫我

如果有任何問題或建議,歡迎隨時聯繫我:

前言

大家好!昨天我們一起探索了 Vue 的互動核心 v-bindv-on,學會了如何讓資料與畫面同步、如何傾聽使用者的操作。現在,我們的應用程式已經有了「互動」的能力。

今天,我們要更進一步,學習如何控制畫面的「結構」。你會學到如何根據不同的條件,決定一個元素是否應該出現在畫面上 (條件渲染),以及如何根據一組資料,動態地產生一整個列表的元素 (列表渲染)。

這兩個強大的指令——v-ifv-for——是所有動態介面的基石。掌握它們,你就能從只能做「靜態頁面」的開發者,蛻變為能打造「動態應用」的工程師。

條件渲染:當畫面需要做選擇時

在開發中,我們經常需要根據某個狀態來決定是否顯示某個區塊。例如:

  • 使用者登入後,顯示「個人資料」;未登入時,顯示「登入按鈕」。
  • 購物車是空的,顯示「您的購物車空無一物」;有商品時,顯示商品列表。

這就是 v-if 的主場。

v-if, v-else, v-else-if:非黑即白,或多重選擇

v-if 會根據一個布林值的表達式來決定是否渲染一個元素。如果表達式為 true,元素就會被建立並插入 DOM;如果為 false,元素就會被銷毀。

<script setup>
import { ref } from 'vue';

const isLoggedIn = ref(false);
</script>

<template>
  <button @click="isLoggedIn = !isLoggedIn">
    {{ isLoggedIn ? '登出' : '登入' }}
  </button>

  <div v-if="isLoggedIn">
    <p>歡迎回來,VIP 使用者!</p>
  </div>
  <div v-else>
    <p>請先登入以查看更多內容。</p>
  </div>
</template>

在這個例子中,div 的顯示與否完全由 isLoggedIn 這個 ref 變數控制。v-else 則提供了一個「備案」,它必須緊跟在 v-ifv-else-if 的元素後面。

v-if vs v-show:真正的銷毀 vs 單純的隱藏

Vue 提供了另一個指令 v-show,它也能根據條件控制元素的可見性。但它和 v-if 有個關鍵的區別:

  • v-if「真正的」條件渲染。如果條件為假,對應的元素會被完全從 DOM 中移除。當條件變為真時,才會重新建立、編譯、並掛載元素。
  • v-show 則是 基於 CSS 的切換。無論條件是真是假,元素始終會被渲染在 DOM 中。v-show 只是簡單地切換元素的 display: none; CSS 屬性。

該用哪個?

  • 效能考量v-if 有更高的「切換開銷」,因為它涉及 DOM 的新增和刪除。v-show 有更高的「初始渲染開銷」,因為它一開始就需要把元素渲染出來。
  • 經驗法則:如果某個元素需要 頻繁地 在顯示和隱藏之間切換(例如,一個可以快速開關的提示框),使用 v-show 效能會更好。如果條件 很少改變(例如,使用者登入狀態),或者你希望確保在條件為假時,元素內的組件完全不會被渲染或執行,那麼 v-if 是更合適的選擇。

列表渲染:當你需要一整排的...任何東西

v-for 讓我們可以基於一個陣列來渲染一個列表。它的語法是 item in items,非常直觀。

基本用法與 :key 的重要性

假設我們有一個待辦事項清單:

<script setup>
import { ref } from 'vue';

const todos = ref([
  { id: 1, text: '學習 Vue' },
  { id: 2, text: '撰寫鐵人賽文章' },
  { id: 3, text: '休息一下' }
]);
</script>

<template>
  <ul>
    <li v-for="todo in todos" :key="todo.id">
      {{ todo.text }}
    </li>
  </ul>
</template>

v-for 會遍歷 todos 陣列,為每個 todo 物件渲染一個 <li> 元素。

注意到了嗎?那個 :key 是什麼?

key 是 Vue 用來識別 VDOM 中每個節點的「身份證」。當你的資料列表更新時(例如新增、刪除、或重新排序),Vue 會使用 key 來匹配新舊節點,以決定如何最高效地更新 DOM。

  • 為什麼不能沒有 key 如果沒有 key,Vue 會採用一種「就地更新」的策略,它會盡量複用相同位置的元素,只更新其內容。這在某些情況下會導致非預期的行為,尤其是在列表包含表單輸入或子組件時。
  • 為什麼不推薦用 indexkey v-for 也提供 (item, index) in items 的語法來獲取索引。但使用 index 作為 key 是非常危險的。想像一下,你刪除了列表中的第一項,原本 index 為 1 的項目現在變成了 index 0,index 為 2 的變成了 1... 所有 key 都亂掉了!這會讓 Vue 感到困惑,可能導致錯誤的 DOM 更新,效能也更差。

最佳實踐:永遠為 v-for 綁定一個 唯一且穩定key,通常是來自你資料的 id

v-ifv-for 一起用?請三思!

一個常見的錯誤是把 v-ifv-for 放在同一個元素上。

<!-- ❌ 不推薦的寫法 -->
<li v-for="user in users" v-if="user.isActive" :key="user.id">
  {{ user.name }}
</li>

為什麼不好? 因為在 Vue 中,v-for 的優先級比 v-if 更高。這意味著,Vue 會先遍歷 所有users,然後在每次迭代中再用 v-if 進行判斷。如果你的 users 陣列有一千個項目,但只有十個是 isActive 的,你依然會遍歷一千次!

正確的做法:

  1. 使用 computed 屬性(推薦):先在 <script> 中把列表過濾好,再用 v-for 渲染過濾後的結果。這讓模板保持乾淨,且效能更好。

    const activeUsers = computed(() => {
      return users.value.filter(user => user.isActive);
    });
    
    <!-- ✅ 推薦的寫法 -->
    <li v-for="user in activeUsers" :key="user.id">
      {{ user.name }}
    </li>
    
  2. 使用 <template> 包裝:如果你不想用 computed,可以將 v-if 移到外層的 <template> 標籤上。

    <template v-for="user in users" :key="user.id">
      <li v-if="user.isActive">
        {{ user.name }}
      </li>
    </template>
    

本篇自我挑戰

  • 思考一:v-if vs v-show 的抉擇
    假設你在設計一個有「編輯模式」和「預覽模式」的個人資料頁面。使用者可以點擊一個按鈕來回切換這兩種模式。你會選擇用 v-if 還是 v-show 來控制這兩個模式的顯示與隱藏?為什麼?

  • 思考二:key 的威力
    想像一個可以讓使用者自由拖曳排序的任務列表。如果這個列表的 v-for 是用 index 作為 key,當使用者拖曳交換了兩個任務的位置後,你覺得 Vue 的更新過程會發生什麼事?如果改用任務的 id 作為 key,又會如何不同?

總結

今天我們學會了 Vue 中控制 DOM 結構的兩大指令:v-ifv-for。它們讓我們能夠根據應用程式的狀態,動態地新增、移除或渲染元素列表。

掌握它們的用法與之間的差異,特別是 v-ifv-show 的選擇,以及為 v-for 提供穩定 key 的重要性,是寫出高效能、可預測 Vue 應用的關鍵。

本日關鍵字回顧

  • v-if, v-else, v-else-if: 條件渲染,會實際新增或銷毀 DOM 節點。
  • v-show: 條件顯示,透過 CSS display 屬性控制可見性。
  • v-for: 列表渲染,用於遍歷陣列並產生元素。
  • :key: 節點的唯一身份標識,對高效的 DOM 更新至關重要。
  • v-forv-if 的優先級: v-for 高於 v-if,避免在同一元素上同時使用。

明天,我們將進入 Vue 最迷人的核心概念之一:組件化。我們將學習如何把介面拆分成一個個可複用的積木,敬請期待!


上一篇
【Day 2】Vue 的核心互動:深入 v-bind 與 v-on 的魔法
下一篇
【Day 4】Vue 的組件化:用 Props 和 Emit 打造你的樂高積木
系列文
Vue 全攻略:30 天技能樹養成13
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言