---
description: Vue3 组合式 API 强制使用规范
globs: ["**/*.vue", "**/composables/**/*.ts"]
alwaysApply: true
---

# Vue3 组合式 API 规范

## 🚫 禁用选项式 API

### 强制使用组合式 API
```vue
<!-- ❌ 禁止使用选项式 API -->
<script>
export default {
  data() {
    return {
      users: [],
      isLoading: false,
    };
  },
  methods: {
    async fetchUsers() {
      this.isLoading = true;
      // ...
    },
  },
};
</script>

<!-- ✅ 必须使用组合式 API -->
<script setup lang="ts">
import { ref, computed, watch, onMounted } from "vue";
import type { IUser } from "@/types/user.types";

// 响应式数据
const users = ref<IUser[]>([]);
const isLoading = ref<boolean>(false);

// 计算属性
const userCount = computed(() => users.value.length);

// 方法
const fetchUsers = async (): Promise<void> => {
  isLoading.value = true;
  try {
    const response = await UserService.getAll();
    users.value = response.data;
  } finally {
    isLoading.value = false;
  }
};

// 生命周期钩子
onMounted(() => {
  fetchUsers();
});
</script>
```

## 🎯 组件设计规范

### Props 定义规范
```vue
<script setup lang="ts">
// ✅ 必须包含类型和默认值
interface Props {
  userId: string
  title: string
  readonly?: boolean
  loading?: boolean
  theme?: 'light' | 'dark'
}

// ✅ 使用 withDefaults 提供默认值
const props = withDefaults(defineProps<Props>(), {
  readonly: false,
  loading: false,
  theme: 'light'
})

// ✅ defineEmits 必须明确事件名称和参数类型
const emit = defineEmits<{
  update: [user: IUser];
  delete: [userId: string];
}>();
</script>
```

## 🏪 Pinia 状态管理规范

### Store 结构组织
```typescript
// stores/user.store.ts
import { defineStore } from "pinia";
import type { IUser, CreateUserInput } from "@/types/user.types";

export const useUserStore = defineStore("user", () => {
  // 状态定义
  const users = ref<IUser[]>([]);
  const currentUser = ref<IUser | null>(null);
  const isLoading = ref<boolean>(false);
  const error = ref<string | null>(null);

  // Actions
  const fetchUsers = async (): Promise<void> => {
    isLoading.value = true;
    error.value = null;

    try {
      const response = await UserService.getAll();
      users.value = response.data;
    } catch (err) {
      error.value = err.message || "获取用户列表失败";
      throw err;
    } finally {
      isLoading.value = false;
    }
  };

  // 返回状态和方法
  return {
    users: readonly(users),
    currentUser: readonly(currentUser),
    isLoading: readonly(isLoading),
    error: readonly(error),
    fetchUsers,
  };
});
```

## ⚡ Vue 3 性能优化规范

### 列表渲染优化
```vue
<template>
  <!-- ✅ 使用 key，优先唯一 ID -->
  <div
    v-for="user in users"
    :key="user.id"
    class="user-item"
  >
    {{ user.name }}
  </div>

  <!-- ❌ 避免使用数组索引作为 key -->
  <div
    v-for="(user, index) in users"
    :key="index"
    class="user-item"
  >
    {{ user.name }}
  </div>
</template>
```

### 条件渲染和组件缓存
```vue
<template>
  <!-- ✅ 频繁切换使用 v-show -->
  <div v-show="isSidebarVisible" class="sidebar">
    <!-- 侧边栏内容 -->
  </div>

  <!-- ✅ 条件渲染使用 v-if -->
  <div v-if="hasPermission">
    <PermissionRequiredContent />
  </div>

  <!-- ✅ Keep-alive 缓存频繁切换的组件 -->
  <keep-alive>
    <UserProfile v-if="currentTab === 'profile'" />
    <UserSettings v-else-if="currentTab === 'settings'" />
    <UserActivity v-else />
  </keep-alive>
</template>
```