iT邦幫忙

2025 iThome 鐵人賽

DAY 12
0
Vue.js

打造銷售系統30天修練 - 全集中・Vue之呼吸系列 第 12

Day 12:[Componentの呼吸・伍之型] Card - 卡片元件設計與實作

  • 分享至 

  • xImage
  •  

在 Day 11,我們為 BaseSelect 建立了完整的測試覆蓋,確保元件在未來修改時不會出現回歸問題。今天我們要繼續我們元件的開發:Card 容器元件的設計與實作。

為什麼需要 Card 元件?

在現代 Web 應用中,Card 是最常見的 UI 模式之一。無論是:

  • 商品展示卡片
  • 功能操作卡片
  • 資訊統計面板
  • 用戶資料卡片

Card 元件提供了一個統一的容器,讓內容有層次感、易於閱讀,並且保持一致的視覺風格。

設計理念:從基礎到進階

我們將採用漸進式設計的理念,先建立一個基礎的 BaseCard 元件,然後基於它建立更專門的 ActionCard 元件。

BaseCard:基礎容器元件

<template>
  <div class="pos-card">
    <div v-if="title" class="pos-card-header">
      <h3 class="pos-card-title">{{ title }}</h3>
      <p v-if="subtitle" class="pos-card-subtitle">{{ subtitle }}</p>
    </div>
    <div class="pos-card-content">
      <slot />
    </div>
  </div>
</template>

<script setup>
    defineProps({
        title: {
            type: String,
            default: '',
        },
        subtitle: {
            type: String,
            default: '',
        },
    });
</script>

<style scoped> ... </style>

設計特點:

  1. 可選標題:支援 title 和 subtitle
  2. 插槽設計:使用 <slot /> 讓內容完全自定義
  3. 語意化結構:header 和 content 分離,符合 HTML 語意

ActionCard:功能卡片元件

基於 BaseCard,我們建立專門用於功能操作的 ActionCard

<template>
  <BaseCard>
    <div :class="['pos-action-card', variant]" @click="$emit('click')">
      <div class="action-icon">
        <component :is="iconComponent" v-if="iconComponent" />
        <div v-else v-html="iconPath"></div>
      </div>
      <div class="action-content">
        <h3 class="action-title">{{ title }}</h3>
        <p class="action-desc">{{ description }}</p>
        <div class="action-stats" v-if="badge">
          <span :class="['stat-badge', variant]">{{ badge }}</span>
        </div>
      </div>
      <div class="action-arrow">
        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
          <polyline points="9 18 15 12 9 6"></polyline>
        </svg>
      </div>
    </div>
  </BaseCard>
</template>

icon 當前實現:直接 SVG 渲染

<div class="action-icon">
  <component :is="iconComponent" v-if="iconComponent" />
  <div v-else v-html="iconPath"></div>
</div>

Prototype 中 icon svg 的寫法:

<svg width="48" height="48" viewBox="0 0 24 24" fill="none">
  <path
    d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"
    stroke="#3b82f6"
    stroke-width="2"
    fill="none"
  ></path>
</svg>

未來優化:ActionIcon 元件化

目前因為是從 prototype 轉過來的,icon 的部分未來其實可以進一步元件化為 ActionIcon 組件

<!-- ActionIcon.vue -->
<template>
  <div class="action-icon" :class="[`action-icon--${variant}`, { 'action-icon--clickable': clickable }]">
    <component :is="iconComponent" v-if="iconComponent" />
    <div v-else v-html="iconPath"></div>
  </div>
</template>
// ...

數據驅動的設計模式

配置化功能卡片

DashBoard.vue 中,我們將硬編碼的卡片替換為數據驅動的方式:

const actionCards = ref([
  {
    id: 'order-management',
    title: '訂單管理',
    description: '查詢、處理現有訂單',
    variant: 'primary',
    badge: '',
    route: 'order-management',
    iconPath: `
      <svg width="48" height="48" viewBox="0 0 24 24" fill="none">
        <circle cx="9" cy="21" r="1" fill="#EF4444"></circle>
        <circle cx="20" cy="21" r="1" fill="#EF4444"></circle>
        <path
          d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"
          stroke="#3b82f6"
          stroke-width="2"
          fill="none"
        ></path>
      </svg>
    `,
  },
  // ... 更多卡片配置
]);

模板簡化

這邊 Prototype 的寫法原本為用html寫死每張 ActionCard 的內容,所以重複的代碼非常多。

改為使用Vue重構,用 v-for 的方式渲染,將原本的 300+ 行重複 HTML 可以縮減為:

<div class="pos-actions-grid">
  <ActionCard
    v-for="card in actionCards"
    :key="card.id"
    :title="card.title"
    :description="card.description"
    :variant="card.variant"
    :badge="card.badge"
    :icon-path="card.iconPath"
    @click="handleActionCardClick(card)"
  />
</div>

Vue 組件化的核心優勢

1. 可重用性 (Reusability)

  • BaseCard 可以在任何需要卡片容器的地方使用
  • ActionCard 專門處理功能操作卡片

2. 可維護性 (Maintainability)

  • 樣式集中管理,修改一處影響全局
  • 邏輯封裝,降低耦合度

3. 可擴展性 (Extensibility)

  • 通過 props 輕鬆添加新功能
  • 支持插槽,內容完全自定義

4. 易測試 (Testability)

  • 組件邏輯獨立,易於單元測試
  • 數據與視圖分離,便於測試不同配置

未來擴展:基於 BaseCard 的卡片組件

基於 BaseCard 的設計理念,我們可以輕鬆延伸出各種專門的卡片組件:

  • CustomerCard:客戶資料卡片
  • NotificationCard:通知訊息卡片
  • StatisticsCard:資料統計卡片 等等...

組件設計的統一性

所有基於 BaseCard 的組件都遵循相同的設計原則:

  1. 統一的容器:使用 BaseCard 提供一致的樣式
  2. 靈活的內容:通過插槽自定義內部結構
  3. 一致的交互:統一的 hover 效果和點擊行為

總結

通過 BaseCardActionCard 的設計,我們展示了 Vue 組件化的核心價值:

  1. 代碼重用:一次編寫,處處使用
  2. 維護性:集中管理,易於修改
  3. 擴展性:靈活配置,適應需求
  4. 一致性:統一風格,提升體驗

在下一篇文章中,我們將探討如何為這些 Card 元件建立完整的測試覆蓋,確保它們在未來修改時不會出現回歸問題。

明日,Day 13:[Componentの呼吸・陸之型] 測試Card - 驗證容器元件功能。心を燃やせ 🔥!


上一篇
Day 11:[Componentの呼吸・肆之型] 測試Select - 確保元件正常運作
下一篇
Day 13:[Componentの呼吸・陸之型] 測試Card - 驗證卡片元件功能
系列文
打造銷售系統30天修練 - 全集中・Vue之呼吸15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言