Communitygithub.com

vue-patterns

Vue.js 3 Composition API 模式、组件架构、响应式最佳实践、Pinia 状态管理、Vue Router 导航和 Nuxt SSR 模式。适用于 Vue、Nuxt、Vite 或 Pinia 项目。在构建或审查 Vue 3、Nuxt 或 Pinia 代码时激活——包括 Composition API、响应式或路由导航。

vue-patterns 是什么?

此技能提供了 Vue.js 3 开发的全面指南,专注于 Composition API (`<script setup>`) 和现代 Vue 生态(Nuxt、Pinia、Vite)。它涵盖了从项目结构(特性优先布局)和组件架构(容器/展示组件、Props 最佳实践、事件)到可复用逻辑 (Composables) 的完整定义与规则。在状态管理方面,推荐使用 Pinia Setup Store 代替 Options Store,并明确了何时使用 `ref()`/`reactive()`、Provide/Inject 或全局 Store。此外,还包括 Vue Router 的导航守卫、响应式路由参数处理,以及 Nuxt 特有的 `useAsyncData`、`useFetch`、Server Routes 和 Runtime Config 模式。该技能还深入探讨了性能优化技巧(如 `v-memo`、`shallowRef`)、测试实践(使用 Vitest 和 Vue Test Utils),以及 Vue 3.5+ 的新 API(如响应式 Props 解构、`useTemplateRef`、`onWatcherCleanup`、`useId()`),并列举了常见的反模式及其解决方案,帮助开发者编写健壮、可维护的 Vue 应用。

兼容平台~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)。
  • 在脚本中使用 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 中清理副作用。
  • 没有模块作用域的副作用。

与 Mixins 对比

Composables 完全取代 Vue 2 mixins:

  • Mixins:不透明的数据流、真理源冲突、命名冲突。
  • Composables:显式导入、清晰的返回值、可组合且可摇树优化。

4. 状态管理

何时使用什么

模式使用场景
ref() / reactive()本地组件状态
Props + Emits父子通信
Provide / Inject主题、配置、插件 API
Pinia store全局、共享、复杂状态
服务端状态 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, // 将 params 作为 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异步组件加载并提供回退内容

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", // 用于缓存的唯一 key
  () => $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() 替代名称匹配的普通 refs 来获取模板引用:

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>

懒加载 Hydration(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执行顺序不明确使用 computed 过滤后的数组
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.

相关技能