前言:从理论到实践
上篇讲了 Skills 的概念和架构,这篇我们动手实践。
作为前端开发者,我会聚焦在前端相关的 Skills 上,包括:
- 如何使用 Skills(Claude Code + VS Code)
- 如何编写 Skills(以 vue-skills 为例)
- 深度拆解 vue-skills 的设计
- 2 个完整的实战案例
第一部分:Skills 使用教程
1.1 在 Claude Code 中使用 Skills
安装 Claude Code:
# macOS / Linux
curl -fsSL https://code.claude.com/install.sh | sh
# Windows (PowerShell)
irm https://code.claude.com/install.ps1 | iex
# 验证安装
claude --version安装 Skills:
# 创建工作目录
mkdir ~/claude-workspace
cd ~/claude-workspace
# 克隆 vue-skills
git clone https://github.com/vuejs-ai/skills.git .claude/skills/vue-skills
# 启动 Claude Code
claude使用 Skills:
> 帮我写一个用户列表组件,要符合 Vue 3 最佳实践Claude Code 会自动调用 vue-skills,生成符合规范的代码。
1.2 在 VS Code 中使用 Skills
安装 Cursor 或 Cline 插件:
Cursor 和 Cline 都支持 Skills,推荐使用 Cline(开源免费)。
配置 Skills 目录:
在项目根目录创建 .skills/ 目录:
mkdir .skills
cd .skills
git clone https://github.com/vuejs-ai/skills.git vue-skills使用:
在 VS Code 中打开 Cline 面板,输入:
> 用 vue-skills 帮我写一个表单组件Cline 会自动加载 vue-skills 并生成代码。
第二部分:如何编写 Skills
2.1 vue-skills 的目录结构
vue-skills/
├── SKILL.md # 核心指令
├── composition-api.md # Composition API 规范
├── reactivity.md # 响应式系统规范
├── vueuse.md # VueUse 最佳实践
└── references/
└── vue3-migration-guide.md # Vue 3 迁移指南为什么这样设计?
- SKILL.md 作为入口:简洁明了,< 500 行
- 按主题拆分子文档:避免单个文件过长
- references/ 放详细文档:按需加载
2.2 SKILL.md 的结构
---
name: vue-skills
description: |
Vue 3 开发最佳实践。当需要编写或审查 Vue 组件时使用。
触发条件:
- 用户说"写 Vue 组件"
- 用户说"审查 Vue 代码"
- 用户说"优化 Vue 组件"
---
# Vue 3 开发最佳实践
## 核心规则
### 1. 必须使用 Composition API
详见 composition-api.md
### 2. 响应式数据规范
详见 reactivity.md
### 3. 优先使用 VueUse
详见 vueuse.md
## 快速检查清单
- [ ] 使用 `<script setup>` 语法
- [ ] Props 和 Emits 有完整的 TypeScript 类型
- [ ] 优先使用 VueUse 组合式函数
- [ ] 避免解构 reactive 对象
- [ ] ref 的 .value 使用正确关键点:
- description 要清晰触发条件:让 AI 知道什么时候该用
- 核心规则简洁明了:详细内容放子文档
- 快速检查清单:方便 AI 快速验证
2.3 子文档的设计
composition-api.md:
# Composition API 规范
## 必须使用 `<script setup>`
❌ 错误:
\`\`\`vue
<script>
export default {
data() {
return { count: 0 }
}
}
</script>
\`\`\`
✅ 正确:
\`\`\`vue
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
</script>
\`\`\`
## Props 和 Emits 定义
✅ 正确:
\`\`\`vue
<script setup lang="ts">
interface Props {
title: string
count?: number
}
const props = defineProps<Props>()
interface Emits {
(e: 'update', value: number): void
}
const emit = defineEmits<Emits>()
</script>
\`\`\`为什么用示例而非说教?
因为 AI 更容易理解具体的代码示例,而不是抽象的描述。
2.4 与其他前端 Skills 的对比
vue-skills vs react-skills:
| 维度 | vue-skills | react-skills |
|---|---|---|
| 核心关注 | Composition API、响应式 | Hooks、性能优化 |
| 文档结构 | 按主题拆分(composition-api.md、reactivity.md) | 按规则分级(CRITICAL、IMPORTANT、NICE_TO_HAVE) |
| 示例风格 | ❌/✅ 对比 | Before/After 对比 |
共同点:
- 都用 TypeScript
- 都强调最佳实践
- 都提供完整的代码示例
差异点:
- vue-skills 更关注响应式陷阱
- react-skills 更关注性能优化
第三部分:深度拆解 vue-skills
3.1 响应式系统的 5 个陷阱
陷阱 1:解构 reactive 对象
// ❌ 错误:失去响应性
const state = reactive({ count: 0 })
const { count } = state
count++ // 不会触发更新
// ✅ 正确:使用 toRefs
const state = reactive({ count: 0 })
const { count } = toRefs(state)
count.value++ // 触发更新陷阱 2:ref 的 .value
// ❌ 错误:忘记 .value
const count = ref(0)
console.log(count) // RefImpl 对象
// ✅ 正确:使用 .value
const count = ref(0)
console.log(count.value) // 0陷阱 3:reactive 数组的直接赋值
// ❌ 错误:失去响应性
const list = reactive([1, 2, 3])
list = [4, 5, 6] // 失去响应性
// ✅ 正确:使用数组方法
const list = reactive([1, 2, 3])
list.splice(0, list.length, 4, 5, 6)陷阱 4:watch 的深度监听
// ❌ 错误:无法监听到变化
const state = reactive({ nested: { count: 0 } })
watch(() => state.nested, () => {
console.log('changed')
}) // 不会触发
// ✅ 正确:使用 deep 选项
watch(() => state.nested, () => {
console.log('changed')
}, { deep: true })陷阱 5:computed 的副作用
// ❌ 错误:在 computed 中修改状态
const count = ref(0)
const doubled = computed(() => {
count.value++ // 副作用!
return count.value * 2
})
// ✅ 正确:computed 只做计算
const count = ref(0)
const doubled = computed(() => count.value * 2)vue-skills 的价值:
把这些陷阱写进 Skill,AI 就会自动避免这些问题。
3.2 VueUse 最佳实践
原则:优先使用 VueUse,避免重复造轮子
场景 1:LocalStorage
// ❌ 错误:手动实现
const count = ref(0)
const stored = localStorage.getItem('count')
if (stored) count.value = JSON.parse(stored)
watch(count, (val) => {
localStorage.setItem('count', JSON.stringify(val))
})
// ✅ 正确:使用 VueUse
import { useLocalStorage } from '@vueuse/core'
const count = useLocalStorage('count', 0)场景 2:窗口尺寸
// ❌ 错误:手动实现
const width = ref(window.innerWidth)
const handleResize = () => {
width.value = window.innerWidth
}
onMounted(() => window.addEventListener('resize', handleResize))
onUnmounted(() => window.removeEventListener('resize', handleResize))
// ✅ 正确:使用 VueUse
import { useWindowSize } from '@vueuse/core'
const { width } = useWindowSize()场景 3:防抖
// ❌ 错误:手动实现
let timer: NodeJS.Timeout
const handleInput = (e: Event) => {
clearTimeout(timer)
timer = setTimeout(() => {
// 处理逻辑
}, 300)
}
// ✅ 正确:使用 VueUse
import { useDebounceFn } from '@vueuse/core'
const handleInput = useDebounceFn((e: Event) => {
// 处理逻辑
}, 300)VueUse 提供了 200+ 组合式函数,覆盖了大部分常见场景。
3.3 类型安全的最佳实践
原则:Props 和 Emits 必须有完整的 TypeScript 类型
<script setup lang="ts">
// ✅ 正确:完整的类型定义
interface Props {
title: string
count?: number
items: Array<{ id: number; name: string }>
}
const props = withDefaults(defineProps<Props>(), {
count: 0
})
interface Emits {
(e: 'update', value: number): void
(e: 'delete', id: number): void
}
const emit = defineEmits<Emits>()
// 使用
emit('update', props.count + 1) // 类型安全
emit('delete', 123) // 类型安全
</script>复杂类型抽离到单独文件:
// types/user.ts
export interface User {
id: number
name: string
email: string
}
// UserList.vue
<script setup lang="ts">
import type { User } from './types/user'
interface Props {
users: User[]
}
const props = defineProps<Props>()
</script>第四部分:实战案例
4.1 案例 1:使用 VueUse Skills 优化表单
需求:
写一个用户注册表单,要符合 Vue 3 最佳实践。
使用 Skills:
> 用 vue-skills 和 vueuse-skills 帮我写一个注册表单生成的代码:
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useLocalStorage, useDebounceFn } from '@vueuse/core'
interface FormData {
username: string
email: string
password: string
}
// 使用 VueUse 的 useLocalStorage 自动持久化
const formData = useLocalStorage<FormData>('register-form', {
username: '',
email: '',
password: ''
})
// 邮箱验证
const isEmailValid = computed(() => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
return emailRegex.test(formData.value.email)
})
// 密码强度
const passwordStrength = computed(() => {
const password = formData.value.password
if (password.length < 6) return 'weak'
if (password.length < 10) return 'medium'
return 'strong'
})
// 防抖的用户名检查
const checkUsername = useDebounceFn(async (username: string) => {
const response = await fetch(`/api/check-username?name=${username}`)
const { available } = await response.json()
return available
}, 300)
// 提交表单
const handleSubmit = async () => {
if (!isEmailValid.value) {
alert('邮箱格式不正确')
return
}
const response = await fetch('/api/register', {
method: 'POST',
body: JSON.stringify(formData.value)
})
if (response.ok) {
// 注册成功,清除缓存
formData.value = { username: '', email: '', password: '' }
}
}
</script>
<template>
<form @submit.prevent="handleSubmit">
<input v-model="formData.username" placeholder="用户名" />
<input v-model="formData.email" placeholder="邮箱" />
<span v-if="!isEmailValid && formData.email">邮箱格式不正确</span>
<input v-model="formData.password" type="password" placeholder="密码" />
<span>密码强度:{{ passwordStrength }}</span>
<button type="submit">注册</button>
</form>
</template>Skills 的价值:
- 自动使用
useLocalStorage持久化表单数据 - 自动使用
useDebounceFn防抖 - 使用
computed做验证 - 类型安全的表单数据
4.2 案例 2:使用 react-skills 优化性能
需求:
优化一个 React 仪表盘组件的性能。
使用 Skills:
> 用 react-skills 帮我优化这个组件的性能优化前:
'use client'
import { useEffect, useState } from 'react'
export default function Dashboard() {
const [user, setUser] = useState(null)
const [posts, setPosts] = useState([])
const [comments, setComments] = useState([])
useEffect(() => {
// 请求瀑布:串行获取数据
fetch('/api/user').then(res => res.json()).then(data => {
setUser(data)
fetch(`/api/posts?userId=${data.id}`)
.then(res => res.json())
.then(posts => {
setPosts(posts)
fetch(`/api/comments?postId=${posts[0].id}`)
.then(res => res.json())
.then(setComments)
})
})
}, [])
return <div>...</div>
}优化后:
// Server Component(无需 'use client')
export default async function Dashboard() {
// 并行获取数据,消除请求瀑布
const [user, posts, comments] = await Promise.all([
fetch('/api/user').then(res => res.json()),
fetch('/api/posts').then(res => res.json()),
fetch('/api/comments').then(res => res.json())
])
return <div>...</div>
}优化效果:
| 指标 | 优化前 | 优化后 | 提升 |
|---|---|---|---|
| 加载时间 | 3.5s | 1.2s | ⬆️ 2.9x |
| 请求数 | 3 次串行 | 3 次并行 | - |
Skills 的价值:
- 自动识别请求瀑布
- 建议使用 Server Components
- 使用 Promise.all 并行请求
4.3 案例 3:创建团队代码审查 Skill
需求:
团队有自己的代码审查规范,希望 AI 能自动审查。
规范要点:
- 必须使用 TypeScript
- 必须有单元测试
- 函数复杂度不超过 10
创建 Skill:
---
name: team-code-review
description: |
团队代码审查。自动检查代码是否符合团队规范。
---
# 团队代码审查
## 审查流程
### 1. TypeScript 检查
- 所有文件必须是 .ts 或 .tsx
- 禁止使用 any 类型
- 禁止使用类型断言(as)
### 2. 单元测试检查
- 每个源文件必须有对应的测试文件
- 测试文件命名:.test.ts 或 .spec.ts
- 测试覆盖率 ≥ 80%
### 3. 函数复杂度检查
- 使用 ESLint 的 complexity 规则
- 阈值:10
- 超过阈值的函数必须拆分
## 审查报告格式
\`\`\`markdown
# 代码审查报告
## ✅ TypeScript 使用
- 所有文件都使用 TypeScript
## ❌ 单元测试
- 缺少测试文件:src/utils/helper.ts
## ✅ 函数复杂度
- 所有函数复杂度 ≤ 10
\`\`\`使用:
> 帮我审查这个项目的代码AI 会自动按照 Skill 里的流程审查代码,并生成报告。
4.4 案例 4:创建业务逻辑开发 Skill
需求:
写一个电商系统的订单处理逻辑,要符合团队规范。
创建 Skill:
---
name: ecommerce-order
description: |
电商订单处理逻辑。当需要写订单相关的业务逻辑时使用。
---
# 电商订单处理
## 订单状态流转
\`\`\`
待支付 → 已支付 → 待发货 → 已发货 → 已完成
↓
已取消
\`\`\`
## 核心规则
### 1. 订单创建
- 必须验证库存
- 必须锁定库存
- 必须生成唯一订单号
### 2. 订单支付
- 必须验证订单状态(待支付)
- 必须调用支付网关
- 必须记录支付日志
### 3. 订单发货
- 必须验证订单状态(已支付)
- 必须生成物流单号
- 必须发送发货通知
## 代码模板
\`\`\`typescript
interface Order {
id: string
userId: string
items: OrderItem[]
status: OrderStatus
totalAmount: number
createdAt: Date
}
enum OrderStatus {
PENDING = 'pending',
PAID = 'paid',
SHIPPED = 'shipped',
COMPLETED = 'completed',
CANCELLED = 'cancelled'
}
class OrderService {
async createOrder(userId: string, items: OrderItem[]): Promise<Order> {
// 1. 验证库存
await this.checkInventory(items)
// 2. 锁定库存
await this.lockInventory(items)
// 3. 生成订单
const order = await this.generateOrder(userId, items)
return order
}
async payOrder(orderId: string): Promise<void> {
// 1. 验证订单状态
const order = await this.getOrder(orderId)
if (order.status !== OrderStatus.PENDING) {
throw new Error('订单状态不正确')
}
// 2. 调用支付网关
await this.callPaymentGateway(order)
// 3. 更新订单状态
await this.updateOrderStatus(orderId, OrderStatus.PAID)
// 4. 记录日志
await this.logPayment(orderId)
}
}
\`\`\`使用:
> 用 ecommerce-order skill 帮我写订单处理逻辑AI 会自动按照 Skill 里的规范生成代码。
第五部分:最佳实践
5.1 优质 Skills 检查清单
元数据:
- name 简洁明确
- description 包含触发条件
- description 包含适用场景
文档结构:
- SKILL.md < 500 行
- 有清晰的章节结构
- 有具体的代码示例(❌/✅ 对比)
- 有错误处理说明
代码质量:
- 脚本放在 scripts/ 目录
- 脚本有清晰的命名
- 脚本有错误处理
5.2 5 个实用开发技巧
技巧 1:description 要清晰触发条件
---
description: |
当用户说"写 Vue 组件"、"审查 Vue 代码"时使用。
---技巧 2:用示例而非抽象描述
❌ 错误:避免解构 reactive 对象
✅ 正确:
\`\`\`typescript
const state = reactive({ count: 0 })
const { count } = toRefs(state)
\`\`\`技巧 3:控制 SKILL.md 在 500 行以内
超过 500 行,拆分为子文档。
技巧 4:写清楚判断条件和错误处理
## 执行前检查
- [ ] 确认项目使用 Vue 3
- [ ] 确认已安装 VueUse
## 错误处理
### 错误 1:未安装 VueUse
提示:检测到项目未安装 VueUse,是否需要安装?技巧 5:测试边缘情况
## 边缘情况
### 情况 1:用户上传的文件格式不支持
处理:自动转换为支持的格式5.3 常见问题与解决方案
问题 1:Skill 不被触发
原因: description 不够清晰
解决:
---
description: |
触发条件:
- 用户说"写 Vue 组件"
- 用户说"审查 Vue 代码"
---问题 2:Token 消耗过大
原因: SKILL.md 太长
解决: 拆分子文档,把详细内容放 references/
问题 3:多个 Skills 冲突
原因: 触发条件重叠
解决: 在 description 中明确区分场景
总结:从 0 到 1 创建你的第一个 Skill
核心要点
使用 Skills
- Claude Code:功能完整
- VS Code + Cline:开源免费
编写 Skills
- SKILL.md < 500 行
- 用示例而非说教
- 写清楚触发条件
vue-skills 的设计
- 按主题拆分子文档
- 5 个响应式陷阱
- VueUse 最佳实践
实战案例
- VueUse 优化表单
- react-skills 优化性能
- 团队代码审查
- 业务逻辑开发
推荐学习路径
第一步:体验(1-2 天)
- 安装 Claude Code 或 Cline
- 克隆 vue-skills
- 试用 3-5 次
第二步:创建(1-2 天)
- 选择一个重复性工作
- 梳理流程
- 创建第一个 Skill
第三步:优化(1 周)
- 研读 vue-skills 的设计
- 总结最佳实践
- 优化自己的 Skill
参考资料
- 本文链接:https://fridolph.top/posts/2026-01-30__ai-skills-2
- 版权声明:本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 许可协议。