Communitygithub.com

vue-patterns

Vue.js 3 Composition API 模式、元件架構、響應式最佳實踐、Pinia 狀態管理、Vue Router 導航及 Nuxt SSR 模式。適用於 Vue、Nuxt、Vite 或 Pinia 專案。在建置或審查 Vue 3、Nuxt 或 Pinia 程式碼時啟用。

vue-patterns 是什麼?

這份技能提供了一份全面且結構化的指南,專為使用 Vue.js 3 的 `<script setup>` 語法與 Composition API 進行開發而設計。內容涵蓋了從專案結構、元件架構、可複用邏輯(Composables)、狀態管理(Pinia)、路由(Vue Router)到效能優化與測試等所有核心面向。對於使用 Nuxt 框架的開發者,也區分並說明了其特有的 SSR 模式與自動匯入等功能。 此技能的一大亮點是涵蓋了 Vue 3.5+ 的最新 API,例如響應式 Props 解構、`useTemplateRef()`、`onWatcherCleanup()` 和 `useId()`,確保開發者能掌握最新的最佳實務。此外,技能內建了一份完整的「反模式」清單,明確指出常見錯誤及其修正方式,能有效協助開發者避免陷阱,寫出更健壯、可維護的程式碼。 適用於 Claude Code、Cursor 等支援自訂技能的 AI 代理工具,當開發者正在進行 Vue 相關專案、需要重構或審查程式碼時,此技能可提供精準且即時的指引。透過遵循其結構化的規則與範例,AI 代理能夠生成符合業界標準的 Vue 3 應用程式。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/vue-patterns

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

Vue.js 模式與最佳實務

使用 Composition API(<script setup>)進行 Vue.js 3 開發的全面指南,涵蓋元件設計、響應式、狀態管理、路由、測試以及 SSR 模式。若與標準 Vue 有所差異,也會提供 Nuxt 專用的指引。

何時啟用

在以下情況啟用此技能:

  • 專案使用了 Vue.js (任何版本)、Nuxt、Vite + Vue 或 Pinia。
  • 使用者詢問關於 Vue 元件架構、Composables、響應式或狀態管理的問題。
  • 審查 Vue 單一檔案元件 (.vue 檔案)。
  • 設定 Vue Router、Pinia stores 或 Vite/Vitest 配置。
  • 討論 Vue 相關的效能、安全性或 SSR 模式。

1. 專案結構

推薦佈局(功能優先)

src/
├── api/              # API 客戶端與端點定義
├── assets/           # 靜態資源 (圖片、字體、圖示)
├── components/       # 共享/可複用元件
│   ├── base/         # 基礎 UI 原語 (Button, Input, Modal)
│   └── features/     # 功能特定共享元件
├── composables/      # 可複用的 Composition API 邏輯
├── layouts/          # 頁面佈局 (可選)
├── pages/            # 路由層級頁面元件
├── router/           # Vue Router 配置
├── stores/           # Pinia stores
├── types/            # TypeScript 型別定義
├── utils/            # 純工具函式
└── App.vue           # 根元件

檔案命名

慣例使用時機
PascalCase.vue所有元件 (由 vue/multi-word-component-names 強制)
useCamelCase.tsComposables
camelCase.ts工具函式、API 客戶端、型別
kebab-case 目錄路由區段、功能資料夾

2. 元件架構

單一檔案元件順序

<script setup lang="ts">
// 1. 匯入 (vue → 生態系 → 絕對路徑 → 相對路徑)
// 2. Props & Emits & Slots
// 3. Composables
// 4. 局部狀態 (ref/reactive)
// 5. 計算屬性
// 6. 方法
// 7. 監聽器
// 8. 生命週期鉤子
</script>

<template>
  <!-- 模板內容 -->
</template>

<style scoped>
  /* 作用域樣式 */
</style>

展示型 vs 容器型

  • 容器元件:負責資料獲取、狀態與副作用。渲染展示型元件。
  • 展示型元件:接收 props,觸發事件。不做 API 呼叫,不存取 store。純渲染。

Props 最佳實務

// 基於型別的 props 搭配預設值
interface Props {
  label: string;
  variant?: "primary" | "secondary";
  disabled?: boolean;
  items: Item[];
}

const props = withDefaults(defineProps<Props>(), {
  variant: "primary",
  disabled: false,
});
  • 永遠提供 type,以及適當的 required/default。
  • 布林 props:isXxx、hasXxx、canXxx。
  • 永不直接修改 props — 改為觸發事件。
  • 對於 v-model 綁定,使用 defineModel() (Vue 3.4+) 或 modelValue + update:modelValue。

事件

const emit = defineEmits<{
  submit: [];
  "update:modelValue": [value: string];
  select: [id: string, index: number];
}>();
  • 在模板中使用 kebab-case (@update:model-value)。
  • 在 script 中使用 camelCase (emit("update:modelValue", val))。

3. Composables (可複用邏輯)

結構

// composables/useDebounce.ts
export function useDebounce<T>(value: MaybeRef<T>, delay: number): Ref<T> {
  const debounced = ref(toValue(value)) as Ref<T>;

  let timer: ReturnType<typeof setTimeout>;
  watch(
    () => toValue(value),
    (newVal) => {
      clearTimeout(timer);
      timer = setTimeout(() => { debounced.value = newVal; }, delay);
    }
  );

  onUnmounted(() => clearTimeout(timer));
  return readonly(debounced);
}

規則

  • 必須以 use 前綴開頭。
  • 回傳響應式值 (ref、computed、reactive),永遠不回傳純原始型別。
  • 透過 MaybeRef / toRef() / toValue() 接受響應式輸入。
  • 在 onUnmounted 或監聽器的 onCleanup 中清理副作用。
  • 避免模組作用域的副作用。

vs Mixins

Composables 完全取代了 Vue 2 的 mixins:

  • Mixins:資料流不透明、資料來源衝突、名稱衝突。
  • Composables:顯式匯入、清晰的回傳值、可組合且可 tree-shaking。

4. 狀態管理

何時使用何種模式

模式使用場景
ref() / reactive()局部元件狀態
Props + Emits父子元件通訊
Provide / Inject主題、配置、外掛 API
Pinia store全域、共享、複雜狀態
Server state composable帶快取的 API 資料 (包裝 fetch/TanStack Query)

Pinia Setup Store (首選)

// stores/useCartStore.ts
export const useCartStore = defineStore("cart", () => {
  const items = ref<CartItem[]>([]);
  const isLoading = ref(false);

  const totalPrice = computed(() =>
    items.value.reduce((sum, i) => sum + i.price * i.quantity, 0)
  );
  const itemCount = computed(() =>
    items.value.reduce((sum, i) => sum + i.quantity, 0)
  );

  async function addItem(productId: string) {
    isLoading.value = true;
    try {
      const item = await fetchProduct(productId);
      const existing = items.value.find(i => i.id === item.id);
      if (existing) existing.quantity++;
      else items.value.push({ ...item, quantity: 1 });
    } finally {
      isLoading.value = false;
    }
  }

  return { items, isLoading, totalPrice, itemCount, addItem };
});
  • 使用 Setup Store 語法 (非 Options Store)。
  • 對於商業邏輯層級的資料變更,偏好使用 actions;對於批量更新,使用 $patch()。
  • 每個非同步 action:處理 loading + success + error。

5. Vue Router

路由定義

const routes = [
  {
    path: "/users/:id",
    name: "user-detail",
    component: () => import("@/pages/UserDetail.vue"), // 懶加載
    props: true, // 將參數作為 props 傳遞
    meta: { requiresAuth: true },
  },
];

導航守衛

router.beforeEach((to, from) => {
  const { isLoggedIn } = useAuthStore();
  if (to.meta.requiresAuth && !isLoggedIn) {
    return { name: "login", query: { redirect: to.fullPath } };
  }
});

響應式路由參數

當元件保持掛載但路由參數改變時:

const route = useRoute();
const id = computed(() => route.params.id as string);
watch(id, (newId) => fetchItem(newId));

6. 模板模式

模板語法

<!-- v-if/v-else-if/v-else -->
<div v-if="isLoading">載入中...</div>
<div v-else-if="error">錯誤:{{ error }}</div>
<div v-else>{{ content }}</div>

<!-- v-show 用於頻繁切換 -->
<div v-show="isOpen">切換的內容</div>

<!-- v-for 搭配穩定 key -->
<div v-for="item in items" :key="item.id">{{ item.name }}</div>

<!-- 使用計算後的過濾列表 (避免在同一個元素上同時使用 v-if + v-for) -->
<div v-for="item in activeItems" :key="item.id">{{ item.name }}</div>

<!-- 事件處理 -->
<form @submit.prevent="handleSubmit">
  <button type="submit">儲存</button>
</form>

<!-- v-model -->
<input v-model="name" />
<CustomInput v-model="value" v-model:title="title" />

7. 效能

技術使用時機
v-memo很少變動的列表項目
v-once只渲染一次且永遠靜態的內容
shallowRef()整個取代的大型資料結構
shallowReactive()僅頂層屬性需要響應式
用 v-show 替代 v-if頻繁的可見度切換
<KeepAlive :max="10">快取切換的視圖
惰性路由非關鍵路由使用 () => import(...)
Suspense帶有 fallback 的非同步元件載入

8. 測試

技術棧

  • Vitest 用於單元測試與元件測試
  • Vue Test Utils 用於掛載與互動
  • @pinia/testing 用於 store 模擬
  • Playwright 用於端對端測試

元件測試模式

import { mount } from "@vue/test-utils";
import { createPinia, setActivePinia } from "pinia";
import UserCard from "./UserCard.vue";

beforeEach(() => { setActivePinia(createPinia()); });

it("渲染並觸發事件", async () => {
  const wrapper = mount(UserCard, {
    props: { user: { id: "1", name: "Alice" } },
  });
  expect(wrapper.text()).toContain("Alice");
  await wrapper.find("button").trigger("click");
  expect(wrapper.emitted("select")![0]).toEqual(["1"]);
});

9. Nuxt 特定模式

自動匯入

Nuxt 會自動匯入 ref、computed、watch、useFetch、useAsyncData 等。直接使用它們,無需手動匯入。對於非 Nuxt 專案,務必顯式匯入。

useAsyncData / useFetch

const { data: user, pending, error, refresh } = await useAsyncData(
  "user", // 用於快取的唯一鍵
  () => $fetch(`/api/users/${id}`),
);

const { data: posts } = await useFetch("/api/posts", {
  query: { page: 1 },
  key: "posts-page-1", // 去重請求
});

伺服器路由

// server/api/users/[id].ts
export default defineEventHandler(async (event) => {
  const { id } = await getValidatedRouterParams(event, z.object({
    id: z.string().uuid(),
  }).parse);
  // ... 獲取並回傳
});

執行時期配置

// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    // 僅伺服器端
    apiSecret: "",
    // 公開 (暴露給客戶端)
    public: {
      apiBase: "https://api.example.com",
    },
  },
});

10. Vue 3.5+ 新 API

響應式 Props 解構

Vue 3.5 穩定了響應式 Props 解構 — 從 defineProps() 解構的變數會自動變成響應式:

// Vue 3.5+: 解構的 props 是響應式的 (不需要使用 toRefs)
const { count = 0, msg = "hello" } = defineProps<{
  count?: number;
  msg?: string;
}>();

// 限制:無法直接監聽解構的 prop
watch(() => count, (newVal) => { ... }); // 正確 必須傳入 getter

useTemplateRef()

使用 useTemplateRef() 取代基於名稱匹配的普通 ref,用於模板引用:

import { useTemplateRef } from "vue";
const inputEl = useTemplateRef<HTMLInputElement>("input");
// "input" 匹配模板中的 ref="input" 屬性,而非變數名稱

支援動態 ref ID:useTemplateRef(dynamicRefId)。

onWatcherCleanup()

全域可匯入的監聽器清理 API (Vue 3.5+)。必須在監聽器回呼內部同步呼叫:

import { watch, onWatcherCleanup } from "vue";

watch(userId, async (newId) => {
  const controller = new AbortController();
  onWatcherCleanup(() => controller.abort());
  // ... 使用 signal 進行 fetch
});

useId()

SSR 穩定的唯一 ID 產生器,用於表單元素和無障礙功能:

import { useId } from "vue";
const id = useId();

defer Teleport

<Teleport defer> 允許傳送到在同一渲染週期中產生的目標:

<Teleport defer to="#container">內容</Teleport>
<div id="container"></div>

惰性水合 (SSR)

defineAsyncComponent() 現在支援 hydrate 策略:

import { defineAsyncComponent, hydrateOnVisible } from "vue";
const AsyncComp = defineAsyncComponent({
  loader: () => import("./Comp.vue"),
  hydrate: hydrateOnVisible(),
});

反模式

反模式為何錯誤修正方法
解構 defineProps() (Vue < 3.5)捕獲快照,失去響應性透過 props.xxx 存取或使用 toRefs()
watch() 解構後的 prop (Vue 3.5+)編譯時錯誤 — 無法直接監聽解構後的 props使用 getter 包裝:watch(() => count, ...)
在同一元素上使用 v-if + v-for執行順序不明確使用計算後的過濾陣列
v-for 的 key 使用索引重新排序時狀態錯亂使用穩定的資料庫 ID
修改 props違反單向資料流觸發事件或使用 v-model
使用帶有用戶內容的 v-htmlXSS 漏洞使用 DOMPurify 進行清理
在 Vue 3 中使用 Mixins不透明、易衝突替換為 Composables
Composable 中的模組作用域副作用跨實例共享在 onMounted + onUnmounted 中限定作用域
對可替換的狀態使用 reactive()替換會破壞響應性改用 ref()
未清理的監聽器記憶體洩漏、競爭條件使用 onCleanup 或 onWatcherCleanup() (Vue 3.5+)
在新的 Vue 3 程式碼中使用 Options API生態系已轉向 Composition API使用 <script setup>
使用普通 ref 做為模板引用不支援動態 ref,名稱匹配脆弱使用 useTemplateRef() (Vue 3.5+)

相關技能

  • accessibility — ARIA、語意化 HTML、焦點管理
  • frontend-patterns — 跨框架前端架構
  • typescript — 應用於 Vue 專案的 TypeScript 最佳實務
  • coding-standards — 通用程式碼品質標準

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

相關技能