三星云服务
27.14M · 2026-04-12
核心原则:JS/TS领域遵循camelCase(小驼峰)/PascalCase(大驼峰),HTML领域使用kebab-case(连字符),保持项目内命名一致性,提升代码可读性与协作效率。
camelCase,首字母小写,动词开头命名函数(如handleClick、fetchData),名词开头命名变量(如userInfo、goodsList)。UPPER_SNAKE_CASE(全大写下划线分隔),如const API_BASE_URL = 'api.example.com'。kebab-case,如v-focus、v-scroll-to,符合HTML属性命名规范。单文件组件(.vue)内部顺序固定为:template → script → style,每个部分独立成块,结构清晰;template内最多包含一个顶级元素,避免多根节点导致的渲染异常。
<!-- 正确示例 -->
<template>
<div class="user-profile">
<!-- 组件内容 -->
</div>
</template>
<script setup>
// 逻辑代码
</script>
<style scoped>
// 样式代码
</style>
<div v-for="item in list" :key="item.id" v-if="item.visible" @click="handleClick">。PascalCase标签(如),明确区分原生HTML元素;DOM模板中必须使用kebab-case(如),因HTML不区分大小写。<script setup>,拒绝混合语法优先使用<script setup>语法(Vue3推荐),简洁高效;复杂组件(如需要生命周期钩子、Props验证、 emits定义)可结合Options API,但同一项目内语法需统一,禁止混合使用。
导入语句按以下顺序排列,不同类别之间空1行,提升可读性:
<script setup>
// 1. Vue内置API
import { ref, computed, watch } from 'vue';
// 2. 第三方库
import { useUserStore } from 'pinia';
import axios from 'axios';
// 3. 内部组件
import BaseButton from './BaseButton.vue';
import UserCard from '@/components/UserCard.vue';
// 4. 工具函数/常量
import { formatDate } from '@/utils/format';
import { API_BASE_URL } from '@/constants';
// 5. API接口
import { fetchUserInfo } from '@/api/user';
</script>
// 正确示例
const props = defineProps({
// 基础类型定义
userId: {
type: Number,
required: true,
validator: (value) => value > 0 // 验证值为正整数
},
// 布尔类型,推荐前缀is
isDisabled: {
type: Boolean,
default: false
},
// 数组/对象类型,默认值需用函数返回,避免引用共享
goodsList: {
type: Array,
default: () => []
},
userInfo: {
type: Object,
default: () => ({
name: '',
age: 0
})
}
});
// 正确示例
const emit = defineEmits(['updateValue', 'deleteItem']);
// 触发事件(传递单个参数)
const handleValueChange = (value) => {
emit('updateValue', value);
};
// 触发事件(传递复杂参数,封装为对象)
const handleDelete = (id, name) => {
emit('deleteItem', { id, name });
};
// 正确示例(async/await + try/catch)
const fetchUser = async () => {
try {
const res = await fetchUserInfo(); // 调用异步接口
return res.data;
} catch (err) {
console.error('获取用户信息失败:', err);
ElMessage.error('加载失败,请重试');
throw err; // 如需上层处理,可重新抛出错误
}
};
// 错误示例(Promise链式调用)
const fetchUser = () => {
return fetchUserInfo()
.then(res => res.data)
.catch(err => {
console.error('获取用户信息失败:', err);
ElMessage.error('加载失败,请重试');
throw err;
});
};
// 正确示例(interface定义对象结构)
interface Goods {
id: number;
name: string;
price: number;
stock: number;
}
const goods: Goods = { id: 1, name: '手机', price: 5999, stock: 100 };
// 正确示例(type定义联合类型)
type GoodsCategory = 'electronics' | 'clothes' | 'food';
// Props类型定义
interface Props {
userId: number;
isDisabled?: boolean;
}
const props = defineProps<Props>();
// Emits类型定义
const emit = defineEmits<{
(e: 'updateValue', value: string): void;
(e: 'deleteItem', params: { id: number; name: string }): void;
}>();
// stores/user.ts 正确示例
import { defineStore } from 'pinia';
import { fetchUserInfo } from '@/api/user';
export const useUserStore = defineStore('user', () => {
// State:定义状态,使用ref/reactive
const userInfo = ref({
id: 0,
name: '',
avatar: ''
});
const isLogin = ref(false);
// Getters:计算属性,依赖State,只读
const userNickname = computed(() => userInfo.value.name || '未知用户');
// Actions:处理同步/异步操作,修改State
const setUserInfo = (info) => {
userInfo.value = info;
isLogin.value = true;
};
const logout = () => {
userInfo.value = { id: 0, name: '', avatar: '' };
isLogin.value = false;
};
// 异步Action,使用async/await
const loadUserInfo = async (userId) => {
try {
const res = await fetchUserInfo(userId);
setUserInfo(res.data);
} catch (err) {
console.error('加载用户信息失败:', err);
throw err;
}
};
return { userInfo, isLogin, userNickname, setUserInfo, logout, loadUserInfo };
});
// router/index.ts 正确示例
import { createRouter, createWebHistory } from 'vue-router';
const routes = [
{
path: '/',
name: 'home',
component: () => import('@/views/Home.vue'),
meta: { title: '首页', requiresAuth: false }
},
{
path: '/user/:id',
name: 'user-profile',
component: () => import('@/views/UserProfile.vue'),
meta: { title: '用户详情', requiresAuth: true },
props: true // 自动将params转为Props传递给组件
},
{
path: '/404',
name: '404',
component: () => import('@/views/404.vue')
},
{
path: '/:pathMatch(.*)*',
redirect: '/404' // 路由匹配失败,重定向到404
}
];
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes
});
// 全局前置守卫:登录验证
router.beforeEach((to, from, next) => {
const userStore = useUserStore();
if (to.meta.requiresAuth && !userStore.isLogin) {
next('/login');
} else {
document.title = to.meta.title || 'Vue3 项目';
next();
}
});
export default router;
项目目录结构清晰,按功能模块划分,便于维护和协作,推荐目录结构如下:
src/
├── assets/ // 静态资源(图片、字体、图标等),命名使用kebab-case
│ ├── images/
│ ├── fonts/
│ └── icons/
├── components/ // 公共组件
│ ├── base/ // 基础组件(BaseButton、BaseInput等)
│ ├── layout/ // 布局组件(LayoutHeader、LayoutSidebar等)
│ └── business/ // 业务组件(OrderList、GoodsCard等)
├── views/ // 页面视图组件,命名使用PascalCase
│ ├── Home.vue
│ ├── UserProfile.vue
│ └── Order/
│ ├── OrderList.vue
│ └── OrderDetail.vue
├── stores/ // Pinia状态管理,命名使用useXXXStore.ts
│ ├── useUserStore.ts
│ └── useCartStore.ts
├── router/ // 路由配置
│ └── index.ts
├── api/ // API接口封装,按模块划分
│ ├── user.ts
│ └── goods.ts
├── utils/ // 工具函数,命名使用camelCase
│ ├── format.ts
│ └── request.ts
├── constants/ // 常量定义
│ └── index.ts
├── styles/ // 全局样式
│ ├── index.scss
│ └── variables.scss
├── composables/ // 组合式函数,复用逻辑
│ └── useDebounce.ts
└── App.vue // 根组件
采用Conventional Commits标准,提交信息清晰,便于代码审查和版本回溯,格式为:(): 。
// 示例
feat(user): add password reset UI
fix(router): handle 404 redirect
chore(deps): upgrade axios to 1.2.0
docs: update component usage documentation