plugins/languages/typescript/skills/vue/SKILL.md
TypeScript / JavaScript Vue 3.5+ 开发规范,覆盖 Composition API + `<script setup lang="ts">`、Vapor Mode 高性能编译、defineProps 解构 + reactive props、useTemplateRef、defineModel、onWatcherCleanup、Pinia 2 setup-store、Nuxt 4 全栈、Vue Router 4 懒加载、VueUse 12、Volar / vue-tsc 类型推断。Use when 开发 Vue 组件、SFC、composables、stores、Nuxt 页面,或用户提到 "Vue"、"Composition API"、"Pinia"、"Nuxt"、"script setup"、"reactive"、"ref"、"computed"、"SFC"、"v-model"。
npx skillsauth add lazygophers/ccplugin typescript-vueInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
本 skill 同时覆盖 JavaScript 项目;示例以 <script setup lang="ts"> 为主,JS 项目去掉 lang="ts" 与类型即可。
typescript-core — ESM/Vite/Biometypescript-async — AbortController + onUnmountedtypescript-security — v-html + DOMPurify<script setup lang="ts"> (默认)<script setup lang="ts">
import { ref, computed, onMounted, useTemplateRef } from 'vue';
interface User { id: string; name: string }
const users = ref<User[]>([]);
const query = ref('');
const loading = ref(true);
const filtered = computed(() =>
users.value.filter(u => u.name.includes(query.value))
);
const inputRef = useTemplateRef<HTMLInputElement>('input');
onMounted(async () => {
try {
const r = await fetch('/api/users');
if (!r.ok) throw new Error(`HTTP ${r.status}`);
users.value = await r.json();
} catch (e) {
console.error(e);
} finally {
loading.value = false;
inputRef.value?.focus();
}
});
</script>
<template>
<input ref="input" v-model="query" />
<p v-if="loading">Loading…</p>
<UserList v-else :users="filtered" />
</template>
<script setup lang="ts">
// defineProps 解构 — 解构后仍响应式 (3.5+)
const { name, count = 0 } = defineProps<{
name: string;
count?: number;
}>();
// useTemplateRef — 类型安全的 ref (3.5+, 代替字符串 `$refs`)
const list = useTemplateRef<HTMLUListElement>('list');
// defineModel — 双向绑定 (3.4+)
const value = defineModel<string>({ required: true });
// onWatcherCleanup (3.5+) — 替代 watch 内的 onCleanup 参数
import { watch, onWatcherCleanup } from 'vue';
watch(id, async (newId) => {
const ctrl = new AbortController();
onWatcherCleanup(() => ctrl.abort());
const r = await fetch(`/api/u/${newId}`, { signal: ctrl.signal });
});
</script>
无虚拟 DOM、直接生成命令式代码,性能近似 Solid。适合性能敏感页面或微前端组件。
// vite.config.ts
import vue from '@vitejs/plugin-vue';
export default {
plugins: [vue({ features: { vaporMode: true } })],
};
<script setup lang="ts" vapor>
// 该 SFC 编译为 Vapor 模式
</script>
// composables/useFetch.ts
import { ref, watchEffect, onScopeDispose, type Ref } from 'vue';
export function useFetch<T>(url: string | (() => string)) {
const data = ref<T | null>(null);
const error = ref<Error | null>(null);
const loading = ref(true);
let ctrl: AbortController | undefined;
watchEffect(async () => {
ctrl?.abort();
ctrl = new AbortController();
loading.value = true;
try {
const u = typeof url === 'function' ? url() : url;
const r = await fetch(u, { signal: ctrl.signal });
if (!r.ok) throw new Error(`HTTP ${r.status}`);
data.value = await r.json() as T;
} catch (e) {
if ((e as Error).name !== 'AbortError') error.value = e as Error;
} finally {
loading.value = false;
}
});
onScopeDispose(() => ctrl?.abort());
return { data, error, loading };
}
// stores/user.ts
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
export const useUserStore = defineStore('user', () => {
const current = ref<User | null>(null);
const list = ref<User[]>([]);
const isLoggedIn = computed(() => !!current.value);
async function login(creds: { email: string; password: string }) {
const r = await fetch('/api/login', { method: 'POST', body: JSON.stringify(creds) });
current.value = await r.json();
}
function logout() { current.value = null; }
return { current, list, isLoggedIn, login, logout };
});
// nuxt.config.ts
export default defineNuxtConfig({
compatibilityDate: '2025-01-01',
future: { compatibilityVersion: 4 },
modules: ['@pinia/nuxt', '@vueuse/nuxt'],
experimental: { typedPages: true },
});
<!-- pages/users/[id].vue -->
<script setup lang="ts">
const route = useRoute();
const { data: user, error } = await useFetch(`/api/users/${route.params.id}`);
</script>
// server/api/users/[id].get.ts — Nitro server route
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, 'id');
return await db.users.findById(id);
});
import { createRouter, createWebHistory } from 'vue-router';
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: () => import('./pages/Home.vue') },
{ path: '/u/:id', component: () => import('./pages/User.vue'), props: true },
],
});
router.beforeEach((to) => {
const store = useUserStore();
if (to.meta.requiresAuth && !store.isLoggedIn) return { name: 'login' };
});
把 <script setup lang="ts"> 改回 <script setup>,删去类型注解;其它写法(API、composable 结构、Pinia setup store)全部一致。Volar 在 <script setup> 中亦能通过 JSDoc 提供类型提示:
<script setup>
import { ref, computed } from 'vue';
/** @type {import('vue').Ref<User[]>} */
const users = ref([]);
</script>
| 现象 | 应改 | 严重 |
|------|------|------|
| Options API 新代码 | Composition API + <script setup> | 高 |
| Vuex | Pinia 2 setup store | 中 |
| 字符串 ref="..." + $refs | useTemplateRef | 中 |
| Mixin | composable | 高 |
| v-html 无清理 | DOMPurify | 高 |
| watch 内未清理副作用 | onWatcherCleanup | 中 |
| 路由组件不 lazy | () => import(...) | 中 |
| Vue 2 语法 (Vue.extend 等) | Vue 3.5 | 高 |
<script setup> + Composition API (TS 项目用 lang="ts")defineProps 解构 (响应式)useTemplateRef 而非字符串 refonUnmounted / onScopeDispose 清理 AbortController / intervalv-html 经 DOMPurifytools
UI/UX 与布局设计——做界面布局/结构/导航/组件/交互的设计决策。触发:做UI/UX/布局/排版/导航/组件/交互/栅格/响应式/图表选型/字体配对。按媒介路由 HTML/Web、原生 App(iOS/Android/桌面)、CLI、TUI。需后端动态系统不适用;配色/主题/色板走姊妹 skill design-color。
tools
主题与配色设计——做颜色搭配/调色板/主题/品牌色阶/暗模式的设计决策。触发:选配色/调色/主题/色板/品牌色/暗模式/对比度/色盲/UI风格。按媒介路由 HTML/Web(CSS变量)、原生App(平台token)、CLI(ANSI)、TUI(真彩/256/16降级)。保证可访问性(对比度/色盲安全)。需后端动态系统不适用;UI/UX 布局/组件/交互走姊妹 skill design-uiux。
tools
跨任意组件(plugin/skill/agent/command)的验证驱动优化循环纪律 skill。当用户要优化某个已有组件却无明确方向、或要防止改了反而更差(自评乐观偏差 / 多维同改归因失效 / 为凑分加废话膨胀)、或要把一套通用「评分→单变量改→改后验证严格更好才留否则回滚→触顶停」的纪律套到任意组件上时使用。管优化过程本身的纪律(validation gate / ratchet / 独立验证 / 触顶停),不评单组件深度(交 skill-dev),不查插件接线(交 plugin-dev)。仅手动 /optimize-any 触发。
data-ai
两层规则记忆 (基于 .skein/spec)。planning 时 recall 召回相关规则、task finish 后 sediment 沉淀学习 + prune 自动精简过期/重复/断链规则。core 常驻硬规 + recall 按需召回, 经判定门自动写盘 (不逐次问用户)。产出 .skein/spec 下 core/recall 规则文件 + index。另支持空仓 bootstrap 播种规则基线、记忆大面积失效 (大重构/换栈) 时 reconstruct 可逆归档后按项目类型分型重建、maintain 手动体检 (超预算/stale/断链/重复/废弃, --apply 自动修复)、auto-fix (Stop hook 写 .pending-fix 标记 → main 派 skein-specer bg 跑 maintain --apply 全自动修, 断链只报告)。