---
name: vue-component-patterns
description: Vue 3 组件开发模式,包括 Composition API、Props/Emits 定义、组件命名规范。适用于开发 Vue 组件时。
基于 Vue Vben Admin 项目的 Vue 3 组件开发规范。
项目使用 Vue 3.5 + TypeScript + <script setup> 语法。
<script lang="ts" setup>
import type { PropsType } from './types';
import { ref, computed } from 'vue';
// 1. 组件命名(必须)
defineOptions({ name: 'ComponentName' });
// 2. Props 定义
interface Props {
userId: number;
userName?: string;
}
const props = withDefaults(defineProps<Props>(), {
userName: '',
});
// 3. Emits 定义
interface Emits {
(e: 'update', value: string): void;
(e: 'delete', id: number): void;
}
const emit = defineEmits<Emits>();
// 4. 响应式状态
const loading = ref(false);
// 5. 计算属性
const displayName = computed(() => props.userName || '未命名');
// 6. 方法
function handleSubmit() {
emit('update', displayName.value);
}
</script>
<template>
<div class="component-name">
<!-- 模板内容 -->
</div>
</template>
<style lang="scss" scoped>
.component-name {
/* 样式 */
}
</style>
// ✅ 正确:使用 import type 导入类型
import type { UserInfo } from '#/api/system/user';
// ✅ 正确:定义具体接口
interface Props {
userId: number;
userName?: string;
}
// ❌ 错误:使用 any
const data: any = {};
// ✅ 正确:使用 unknown + 类型守卫
function getErrorMessage(error: unknown): string {
if (error instanceof Error) {
return error.message;
}
return '未知错误';
}
标准 CRUD 页面的文件结构:
views/
└── system/
└── user/
├── index.vue # 列表页
├── data.ts # 数据定义(表格列、表单 Schema)
└── modules/
├── form.vue # 表单弹窗
└── detail.vue # 详情弹窗(可选)
| 文件位置 | 导入层级 |
|---|---|
index.vue |
4 层 ../.. |
modules/form.vue |
5 层 ../../.. |
// index.vue 中的导入
import { useFormSchema } from '../data';
// modules/form.vue 中的导入
import { useFormSchema } from '../../data';
| 类型 | 命名规则 | 示例 |
|---|---|---|
| 页面组件 | 与目录名一致 | UserList.vue |
| 业务组件 | 功能名 + 类型 | UserSelect.vue |
| 基础组件 | 功能名 | Button.vue |
| 弹窗组件 | 功能 + Form/Detail | UserForm.vue |
<template>
<!-- 优先使用 Tailwind CSS -->
<div class="flex items-center p-4 bg-white rounded-lg">
<span class="text-base font-medium text-gray-900">标题</span>
</div>
</template>
<style lang="scss" scoped>
/* 组件样式使用 scoped */
.component-name {
/* 颜色使用 CSS 变量 */
background-color: var(--component-background);
/* 覆盖组件库样式使用 :deep */
:deep(.ant-table) {
border-radius: 8px;
}
}
</style>
defineOptions 定义组件名any 类型withDefaults + defineProps<T>()#/* 指向 ./src/*