iT邦幫忙

2025 iThome 鐵人賽

DAY 5
0
Vue.js

作為 Angular 專家探索 Vue 3 和 Svelte 5系列 第 5

第 4 天 - Vue 3、Svelte 5 與 Angular 19 的清單渲染

  • 分享至 

  • xImage
  •  

清單渲染與刪除按鈕

今天我要示範如何渲染一個項目清單。每列還會有一個刪除按鈕,可以從清單中刪除項目。當清單更新後,模板會反應性地重新渲染清單。

新增了一個 Item 類型,所有應用共用。每個項目有 IDlabelpurchased,和 higherPriority

type Item = {
  id: number;
  label: string;
  purchased: boolean;
  higherPriority: boolean;
}

Vue 3 範例

ShoppingCart 元件的 <script setup lang="ts"> 中,我建立一個 itemsref,給初始值。模板透過 v-for 指令疊代陣列,顯示每個元素。每一列有一個按鈕,尚未綁定事件。事件處理會在後續天數說明。

let items = ref([
  {
    id: 1,
    label: '10 Apples',
    purchased: false,
    higherPriority: false,
  },
  {
    id: 2,
    label: '5 Bananas',
    purchased: false,
    higherPriority: false,
  },
]);

items 是一個反應式陣列,維護購物車的項目列表。當項目被新增或刪除後,清單會自動重新渲染。

<script setup lang="ts">
import { Icon } from "@iconify/vue";
import { ref } from 'vue'

type Item = { ... }

let header = ref('Shopping List App')
let items = ref([...])
</script>

<template>
  <h1>{{ header }}</h1>
  <ul>
    <div class="list-item" v-for="item in items" :key="item.id">
      <li>{{ item.id }} - {{ item.label }}</li>
      <button class="btn btn-cancel" aria-label="Delete">
        <Icon icon="ic:baseline-remove" />
      </button>
    </div>
  </ul>
</template>

v-for 指令用來遍歷 items,顯示每個項目的 IDlabel 屬性。:key 用來追蹤唯一鍵 id,避免清單不必要的重新渲染。

刪除按鈕位於清單項目旁邊,並顯示一個移除圖示。這個按鈕目前沒有功能,因為尚未綁定任何事件處理器。

script 標籤中從 iconify/vue 函式庫匯入了 Icon 元件,並用它來顯示移除圖示。

樣式區塊設定為 scoped,清單項目採用 flex 排版,並在 <li> 元素與按鈕之間加入邊距。

SvelteKit 範例

使用 $state 建立反應式陣列 items,存購物車清單。模板用 #each 語法迭代陣列顯示清單。

let items = $state([
  {
    id: 1,
    label: '10 Apples',
    purchased: false,
    higherPriority: false,
  },
  {
    id: 2,
    label: '5 Bananas',
    purchased: false,
    higherPriority: false,
  },
]);
<script setup lang="ts">
import Icon from "@iconify/svelte";

type Item = { ... }

let header = $state('Shopping List App')
let items = $state([...])
</script>

<template>
  <h1>{ header }</h1>
  <ul>
    {#each items as item (item.id)}
      <div class="list-item">
        <li>{item.id} - {item.label}</li>
        <button class="btn btn-cancel" aria-label="Delete">
          <Icon icon="ic:baseline-remove" />
        </button>
      </div>
    {/each}
  </ul>
</template>

#each 內建區塊用來遍歷 items,顯示每個項目的 IDlabel 屬性。陣列元素的別名為 item,唯一鍵為 (item.id)

刪除按鈕位於清單項目旁邊,並帶有移除圖示。該按鈕目前沒有任何功能,因為尚未綁定事件處理器。

script 標籤中從 iconify/svelte 函式庫匯入了 Icon 元件,並在使用時顯示移除圖示。

style 標籤內的樣式均為作用域樣式。類似地,清單項目採用 flex 排版,並在 <li> 元素與按鈕間加入邊距。

Angular 19 範例

items = signal<Item[]>([
  {
    id: 1,
    label: '10 Apples',
    purchased: false,
    higherPriority: false,
  },
  {
    id: 2,
    label: '5 Bananas',
    purchased: false,
    higherPriority: false,
  },
]);

我宣告了一個帶有初始 Item 陣列的 items 信號(signal)。signal 函式具有泛型 T,這裡設定為 Item[]@for 控制流程語法負責遍歷 items,並將每個項目顯示在一列中。

@Component({
  selector: 'app-shopping-cart',
  imports: [NgIcon],
  viewProviders: [ provideIcons({ matRemove })],
  template: `
      <h1>{{ header() }}</h1>
      <ul>
          @for (item of items(); track item.id) {
            <div class="list-item">
              <li>{{ item.id }} - {{ item.label }}</li>
              <button class="btn btn-cancel" aria-label="Delete">
                <ng-icon name="matRemove"></ng-icon>
              </button>
            </div>
          }
      </ul>
  `,
  styles: `
    div.list-item {
      display: flex;
    }

    div.list-item > li {
      margin-right: 0.5rem;
    }
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ShoppingCartComponent {
  header = signal('Shopping List App');
  items = signal<Item[]>([... array element …]);
}

與 Vue 3 和 Svelte 5 不同的是,items 信號是在 ShoppingCartComponent 類別中初始化的。 我在元件的 imports 陣列中引入了 NgIcons,並在 viewProviders 陣列中使用了 provideIcons({ matRemove })ng-icon 指令用來在按鈕上顯示移除圖示。

@for 語法用來遍歷 items 信號,將每個清單項目顯示在列表中。@for 中的 track 表達式是必須的,用來追蹤唯一的鍵 ID

此外,Component 裝飾器的 styles 屬性可以用來添加內聯樣式。同樣地,div.list-itemdiv.list-item > li 的內聯樣式會套用到列表和列表項目上。

以上就是今天成功完成的購物車元件清單顯示內容!

Github Repositories

Github Pages


上一篇
第 3 天:在模板中使用表達式
下一篇
第 5 天:元件中的用戶輸入處理
系列文
作為 Angular 專家探索 Vue 3 和 Svelte 519
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言