Files
vibe_coding/.cursor/skills/component-scaffold/SKILL.md
2026-03-05 21:27:11 +08:00

8.3 KiB
Raw Blame History

name, version, description, requires
name version description requires
component-scaffold 4.1.0 生成 Vue 3 SFC 组件脚手架,含单元测试和类型安全 Props。当需要新建组件、拆分子组件或创建复合组件时使用。管理端用 Element Plus用户端用 Headless UI。
vue-testing

⚠️ 核心执行流程已在 .cursor/rules/skill-component-scaffold.mdc 中由 Cursor 自动注入。 本文件提供完整模板、代码示例和边缘场景处理,供 Agent 按需深入 Read。

Vue 3 Component Scaffold

⚠️ 前端识别:生成组件前必须确认目标前端。

  • 管理端 (Case-Database-Frontend-admin/):使用 Element Plus + Tailwind
  • 用户端 (Case-Database-Frontend-user/):使用 Headless UI + Tailwind禁止 Element Plus

触发条件

用户要求创建新的 Vue 组件、页面组件、UI 元素或交互模块。

执行流程

0. 加载规范(⚠️ 必须最先执行)

依次读取 .cursor/rules/010-typescript.mdc.cursor/rules/011-vue.mdc.cursor/rules/019-modular.mdc,提取类型注解要求(隐式 any 禁令、ref 泛型规范、Composable 类型规范、script setup、defineProps/Emits、组件分类、拆分阈值、Composable 提取规则。

Tier 3Vue 3 完整 API 见 references/vue-api-reference.md

0.5 ⚠️ 生成前强制结构规划(禁止跳过)

写代码前必须先输出文件结构和组件职责说明。

A. 检查是否已有可复用的基础组件

在生成新组件前,先扫描以下路径,避免重复造轮子

  • src/components/core/ — 通用基础组件(按钮、输入框、卡片等)
  • src/components/custom/ — 业务定制组件

若已有 FormInput.vueBaseCard.vue 等,直接复用,不重新生成

B. 用户端表单输入:优先复用 FormInput 模式

用户端页面中表单输入框若出现 ≥3 个,必须使用 FormInput 基础组件:

<!-- src/components/core/FormInput/FormInput.vue -->
<script setup>
defineProps({
  modelValue: { type: String, default: '' },
  type: { type: String, default: 'text' },
  placeholder: { type: String, default: '' },
  icon: { type: Object, default: null },      // Lucide 图标组件
  disabled: { type: Boolean, default: false },
  error: { type: String, default: '' },
})
defineEmits(['update:modelValue'])
</script>

<template>
  <div class="relative">
    <component :is="icon" v-if="icon"
      class="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 dark:text-gray-500 w-5 h-5" />
    <input
      :type="type"
      :value="modelValue"
      :placeholder="placeholder"
      :disabled="disabled"
      @input="$emit('update:modelValue', $event.target.value)"
      :class="[
        'w-full border-b py-3 outline-none transition-colors',
        icon ? 'pl-10 pr-4' : 'px-4',
        'bg-transparent border-gray-300 dark:border-[#333333]',
        'text-gray-900 dark:text-white placeholder:text-gray-400 dark:placeholder:text-gray-600',
        'focus:border-[#C41E3A] dark:focus:border-[#C41E3A]',
        error ? 'border-red-500' : '',
      ]"
      data-testid="form-input"
    />
    <p v-if="error" class="mt-1 text-xs text-red-500">{{ error }}</p>
  </div>
</template>

若项目中尚无 FormInput,在生成使用它的页面前先生成该核心组件。

C. 重复 UI 模式检测

检查需求中是否存在重复结构:

场景 检测标准 操作
表单输入项 ≥3 个相同结构的 input 组 提取 FormInput.vue
内容卡片 ≥3 个相同布局的卡片 提取 CaseCard.vue / DesignerCard.vue
操作按钮组 ≥2 处相同按钮组合 提取 ActionGroup.vue
阶段/Tab 面板 ≥2 个结构相同的面板 提取 StagePanel.vue

D. 输出组件文件结构(代码前必须输出)

# 本次将生成以下文件:
src/components/<type>/<ComponentName>/
├── <ComponentName>.vue      ← 主组件(目标 ≤ 120 行)
├── <ComponentName>.test.ts  ← 单元测试
└── index.ts                 ← barrel export

# 依赖(已存在 / 需新建):
- FormInput.vue: [已存在 / 需新建]
- BaseCard.vue: [已存在 / 不需要]

1. 确认组件规格

字段 必填 默认值
组件名
组件类型 UI 组件
所在目录 src/components/
Props / Emits 根据需求推断

类型与目录:coresrc/components/core/customcustom/layoutlayouts/pageviews/<module>/components/formcustom/

2. 扫描项目模式

读取 src/components/ 确认 Props 声明、样式方案、命名前缀约定、已有的 core 组件列表。

3. 生成文件结构

按步骤 0.5 输出的结构逐文件生成,禁止将多个组件合并到一个文件

src/components/<type>/<ComponentName>/
├── <ComponentName>.vue
├── <ComponentName>.test.ts
└── index.ts

4. 组件模板

根据类型选择:基础 UI / 表格 / 表单对话框 / 复合组件。完整模板与设计决策树见 Tier 3

单组件行数限制

  • template 区域 ≤ 80 行
  • script 区域 ≤ 60 行(超出提取 composable
  • 整个 SFC ≤ 150 行(超出必须拆分子组件)

4.5 设计决策树(必须执行)

  • ≥3 布尔 prop→ 显式变体组件
  • 多子组件共享状态?→ provide/inject
  • script 逻辑 > 60 行?→ 提取 use<ComponentName>.ts composable必须遵循 010-typescript.mdc 的 Composable 类型规范:参数有类型、ref 有泛型、业务类型用 import type
  • 2 处复用?→ src/components/ + slot

  • 同一 UI 结构重复 ≥3 次?→ 提取基础组件(见步骤 0.5C
  • 否则 → 基础 UI 模板

5. 测试与 Barrel export

测试至少包含渲染测试。index.ts 导出:export { default as ComponentName } from './ComponentName.vue'。详细测试见 vue-testing 技能。

验证

  1. ESLint 无报错
  2. Props 使用对象语法 defineProps({ key: { type, default } })若模板可直接访问 props 字段则不保存返回值(避免 unused-vars 报错;仅当 script 中需要访问 props.xxx 时才保存:const props = defineProps(...)
  3. Emits 使用数组语法,事件名使用 camelCase非 kebab-case
  4. 包含 data-testid
  5. 测试至少一个渲染测试
  6. 管理端Element Plus 用于组件Tailwind 用于布局用户端Headless UI + Tailwind禁止 Element Plus
  7. barrel export 正确
  8. 单 SFC ≤ 150 行
  9. 重复 UI 结构≥3 次)已提取为基础组件
  10. 表单输入 ≥3 个已复用 FormInput.vue(用户端)
  11. 子组件模板中无 v-model 直接绑定 prop 嵌套属性(参见 011-vue.mdc Props 数据流模式)
  12. 提取的 composableuse.ts参数有类型注解、ref([]) / ref(null) 有泛型标注*(参见 010-typescript.mdc Composable 类型规范)

Red Flags触发则停止并重构

  • 未输出文件结构直接写代码 → 停止,先输出步骤 0.5D 的结构
  • 单 SFC > 150 行 → 拆分子组件
  • 相同 Tailwind 输入框结构写了 ≥3 次 → 提取 FormInput.vue
  • Options API → 改用 <script setup>
  • const props = defineProps(...) 但 script 中从不访问 props.xxx → 去掉 const props =,避免 unused-vars lint 报错
  • catch (e) { ... } 但 catch 块中不使用 e → 改为 catch { ... }(无参 catch避免 unused-vars 报错
  • 直接修改 props → 通过 emit含隐蔽变体v-model="prop.field"v-model="prop[key]"、事件回调中 prop[k] = v
  • watch deep:true 滥用 → 精准监听
  • script 逻辑 > 60 行未提取 → 拆分为 use*.ts
  • composable 参数无类型 / ref([]) 无泛型 → 补全类型注解(strict: true 下必报错)
  • ≥3 布尔 prop 控制渲染 → 拆分变体
  • prop drilling 传递同状态 → 改用 provide/inject

Tier 3 深度参考

文件 内容
references/component-templates.md 基础/表格/表单/复合组件模板、决策树、Prop 反模式、错误处理、UI 反模式
references/vue-api-reference.md Vue 3 完整 API 索引
references/naming-conventions.md 组件命名规范