Vue3 代码编写规范 | 避坑指南+团队协作标准

一、Vue3 通用基础规范(必看!统一编码底线)

1.1 编码格式规范:避免格式混乱,提升代码可读性

  • 缩进:统一使用4个空格缩进(禁止使用Tab),确保不同编辑器渲染一致。
  • 换行:每个独立代码块之间空1行,逻辑相关的代码块紧密排列,提升可读性。
  • 分号:语句结尾统一添加分号,避免因自动分号插入(ASI)导致的语法歧义。
  • 引号:模板内属性使用双引号(""),Script中字符串优先使用单引号(''),特殊场景(如嵌套引号)可灵活切换。
  • 注释:关键逻辑、复杂业务代码必须添加注释,注释需简洁明了,说明"为什么做"而非"做了什么";组件开头可添加类注释,说明组件功能、Props、使用场景。

1.2 命名规范:一眼看懂用途,降低协作成本

核心原则:JS/TS领域遵循camelCase(小驼峰)/PascalCase(大驼峰),HTML领域使用kebab-case(连字符),保持项目内命名一致性,提升代码可读性与协作效率。

  • 变量/函数:使用camelCase,首字母小写,动词开头命名函数(如handleClick、fetchData),名词开头命名变量(如userInfo、goodsList)。
  • 常量:使用UPPER_SNAKE_CASE(全大写下划线分隔),如const API_BASE_URL = 'api.example.com'。
  • 类/组件:使用PascalCase,首字母大写,组件名需为多个单词(根组件App除外),避免与HTML原生元素冲突,如UserProfile、GoodsCard而非Todo、Button。
  • 自定义指令:使用kebab-case,如v-focus、v-scroll-to,符合HTML属性命名规范。

二、Vue3 单文件组件(SFC)规范(核心重点!避坑关键)

2.1 组件结构规范:固定结构,避免渲染异常

单文件组件(.vue)内部顺序固定为:template → script → style,每个部分独立成块,结构清晰;template内最多包含一个顶级元素,避免多根节点导致的渲染异常。

xml 复制代码
<!-- 正确示例 -->
<template>
    <div class="user-profile">
        <!-- 组件内容 -->
    </div>
</template>

<script setup>
// 逻辑代码
</script>

<style scoped>
// 样式代码
</style>

2.2 Template 规范:高效渲染,减少性能损耗

  • 指令使用:v-bind、v-on可使用简写(:、@),v-slot使用#简写;指令顺序统一为:v-for → v-if → v-bind → v-on,如<div v-for="item in list" :key="item.id" v-if="item.visible" @click="handleClick">
  • v-for 要求:必须搭配key,key值需为唯一标识(如id),禁止使用index作为key;避免在v-for内使用v-if,可通过计算属性过滤数据后再渲染,提升性能。
  • 组件引用:模板中使用组件时,优先使用PascalCase标签(如),明确区分原生HTML元素;DOM模板中必须使用kebab-case(如),因HTML不区分大小写。
  • 属性绑定:多个属性分行书写,每个属性占一行,提升可读性;布尔属性直接写属性名,如而非。

2.3 Script 规范:简洁高效,符合Vue3最佳实践

2.3.1 语法选择:优先<script setup>,拒绝混合语法

优先使用<script setup>语法(Vue3推荐),简洁高效;复杂组件(如需要生命周期钩子、Props验证、 emits定义)可结合Options API,但同一项目内语法需统一,禁止混合使用。

2.3.2 导入顺序:规范排序,提升代码可维护性

导入语句按以下顺序排列,不同类别之间空1行,提升可读性:

  1. Vue内置API(如ref、computed、watch);
  2. 第三方库(如Pinia、Axios、Element Plus);
  3. 项目内部组件(如子组件、基础组件);
  4. 工具函数、常量、样式文件;
  5. API接口请求函数。
xml 复制代码
<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>

2.3.3 Props 规范:严谨定义,避免传参异常

  • 命名:Props定义使用camelCase(如userName),模板中传递时使用kebab-case(如user-name),Vue会自动完成转换。
  • 定义:Props需详细定义,至少指定类型;必填项标注required: true,可选值通过validator验证,提升组件可维护性与容错性。
javascript 复制代码
// 正确示例
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
        })
    }
});

2.3.4 Emits 规范:明确声明,避免事件混乱

  • 命名:定义时使用camelCase(如updateValue),模板中监听时使用kebab-case(如@update-value),符合HTML属性命名习惯。
  • 定义:通过defineEmits明确声明组件触发的事件,禁止隐式触发事件;事件参数需清晰,避免传递过多参数,复杂参数建议封装为对象。
ini 复制代码
// 正确示例
const emit = defineEmits(['updateValue', 'deleteItem']);

// 触发事件(传递单个参数)
const handleValueChange = (value) => {
    emit('updateValue', value);
};

// 触发事件(传递复杂参数,封装为对象)
const handleDelete = (id, name) => {
    emit('deleteItem', { id, name });
};

2.3.5 异步逻辑规范:优雅处理,避免报错中断

  • 优先使用async/await语法,禁止使用Promise链式调用(then/catch),代码更易读且便于调试。
  • 所有async/await必须包裹try/catch,或在调用时用.catch()捕获错误,避免控制台报错和逻辑中断;错误处理需友好,可结合UI提示反馈给用户。
  • 高频触发的异步请求(如搜索输入框)必须加防抖,避免无效请求,推荐用组合式函数useDebounce封装复用。
javascript 复制代码
// 正确示例(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;
        });
};

2.3.6 TypeScript 规范:强类型约束,减少类型报错

  • 禁止滥用any类型:除非明确兼容所有类型(如第三方库无类型声明),否则必须用具体类型、unknown或泛型;若用any,需加注释说明原因。
  • 接口(interface)与类型别名(type)区分:定义对象/类的结构用interface(支持扩展、实现);定义联合类型、交叉类型或简单类型别名用type。
  • Props/Emits 类型:使用TypeScript时,优先通过泛型定义Props和Emits类型,提升类型安全性。
typescript 复制代码
// 正确示例(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;
}>();

2.4 Style 规范:避免污染,提升样式复用性

  • 作用域:组件样式优先使用scoped(如),避免样式污染;全局样式统一放在src/styles目录下,禁止在组件内写全局样式(除非特殊需求)。
  • 命名:样式类名使用kebab-case,与组件名、功能对应,如.user-profile、goods-card;避免使用无意义的类名(如box1、content2)。
  • 样式顺序:按"布局 → 尺寸 → 样式 → 交互"的顺序编写,如position → width → background → hover。
  • 复用:公共样式(如颜色、字体、间距)提取为变量,统一管理;重复使用的样式封装为Mixin或自定义样式类,提升复用性。

三、Vue3 组件设计规范(高复用+低耦合,团队必守)

3.1 组件拆分原则:拒绝大组件,提升可维护性

  • 单一职责:一个组件只负责一个功能,避免"大组件"(代码超过500行),复杂功能拆分为多个子组件,如将用户列表拆分为UserList(列表容器)、UserItem(列表项)、UserSearch(搜索框)。
  • 高复用低耦合:可复用组件(如按钮、输入框)提取为基础组件(放在src/components/base目录),组件间通过Props传递数据、Emits触发事件,禁止直接操作父/子组件数据。
  • 命名区分:基础组件统一前缀Base(如BaseButton、BaseInput),业务组件按功能命名(如OrderList、PaymentForm),布局组件前缀Layout(如LayoutHeader、LayoutSidebar)。

3.2 组件通信规范:清晰传参,避免数据混乱

  • 父子组件:父传子用Props,子传父用Emits,禁止子组件直接修改Props(单向数据流);复杂数据可通过v-model双向绑定(Vue3支持多v-model)。
  • 跨层级组件:优先使用Pinia状态管理,或使用provide/inject(适用于深层组件通信,需明确注入类型),禁止使用EventBus(易造成事件混乱)。
  • 同级组件:通过父组件中转(子传父 → 父传另一个子),或使用Pinia共享状态,避免直接通信。

四、Vue3 Pinia 状态管理规范(替代Vuex,简洁高效)

4.1 Store 设计原则:模块化拆分,避免冗余

  • 模块化:按业务模块拆分Store(如userStore、cartStore、goodsStore),避免单一Store过大;Store命名统一前缀use(如useUserStore),使用camelCase命名法。
  • 状态划分:State(状态)、Getters(计算属性)、Actions(异步/同步操作)分离,禁止在Getters中修改State,禁止在组件中直接修改Store的State(需通过Actions)。

4.2 状态操作规范:规范调用,避免状态异常

ini 复制代码
// 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 };
});

五、Vue3 Vue Router 路由规范(优化体验,避免路由踩坑)

  • 路由命名:路由name使用kebab-case(如user-profile),与组件名、路径对应,提升可读性;路由path使用kebab-case(如/user/profile),符合URL命名规范。
  • 路由懒加载:所有路由组件均使用懒加载(() => import('组件路径')),减少首屏加载时间;基础组件无需懒加载。
  • 路由守卫:全局守卫用于权限控制(如登录验证),路由独享守卫用于单个路由的特殊控制,组件内守卫用于组件内的生命周期控制;避免在守卫中写复杂业务逻辑。
  • 参数传递:路径参数(params)用于必填参数(如/user/:id),查询参数(query)用于可选参数(如/list?page=1&size=10);接收参数时需做类型校验。
javascript 复制代码
// 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;

六、Vue3 工程化与协作规范(团队高效协作必备)

6.1 文件目录规范:结构清晰,便于维护

项目目录结构清晰,按功能模块划分,便于维护和协作,推荐目录结构如下:

scss 复制代码
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          // 根组件

6.2 代码提交规范(Git Commit):清晰可追溯,便于审查

采用Conventional Commits标准,提交信息清晰,便于代码审查和版本回溯,格式为:(): 。

  • type(提交类型):feat(新功能)、fix(Bug修复)、docs(文档变更)、style(代码样式调整,不影响逻辑)、refactor(重构,不修复Bug也不增加功能)、test(测试相关)、chore(构建/工具变更)。
  • scope(范围):指定提交影响的模块(如user、router、goods),无明确范围可省略。
  • subject(描述):简洁明了,说明提交内容,首字母小写,结尾不加句号。
scss 复制代码
// 示例
feat(user): add password reset UI
fix(router): handle 404 redirect
chore(deps): upgrade axios to 1.2.0
docs: update component usage documentation

6.3 代码校验规范:统一格式,减少冲突

  • 工具配置:项目必须集成ESLint、Prettier,统一代码格式;安装依赖:npm install -D eslint prettier eslint-plugin-vue @typescript-eslint/parser eslint-config-prettier husky lint-staged。
  • 自动校验:配置pre-commit钩子(husky + lint-staged),提交代码时自动校验格式,不符合规范的代码禁止提交;开发过程中使用编辑器插件(如ESLint、Prettier)实时校验。
  • ESLint配置:继承vue3-recommended规范,结合项目需求调整规则,禁止禁用必要的校验规则(如禁止滥用any、禁止Props修改)。

七、Vue3 性能与安全规范(优化体验+规避风险)

7.1 性能优化规范:提速降耗,提升用户体验

  • 响应式优化:避免过度使用reactive,简单数据使用ref;大数据列表使用v-virtual-scroller(虚拟滚动),减少DOM渲染数量。
  • 计算属性与监听:computed用于依赖状态的计算(缓存结果),watch用于监听状态变化并执行副作用(如请求接口);避免在watch中写复杂逻辑,避免监听过多状态。
  • 资源优化:静态资源(图片)压缩,使用CDN加载;路由懒加载、组件懒加载;避免重复请求(添加请求缓存、防抖节流)。
  • DOM优化:减少DOM操作,避免在模板中使用复杂表达式;使用v-show替代v-if(频繁切换场景),v-if替代v-show(一次性渲染场景)。

7.2 安全规范:规避漏洞,保障项目稳定

  • XSS防护:避免直接插入HTML(如v-html),若必须使用,需对内容进行过滤;禁止使用eval、with等危险语法。
  • 接口安全:请求接口时添加token验证;敏感数据(如密码)加密后传输;接口返回数据需做类型校验,避免恶意数据导致的报错。
  • 依赖安全:定期更新项目依赖,避免使用存在安全漏洞的依赖包;安装依赖前检查依赖安全性(如使用npm audit)。

八、Vue3 补充规范(细节拉满,避免踩坑)

  • 兼容性:兼容主流浏览器(Chrome、Edge、Firefox最新版本),如需兼容旧浏览器(如IE11),需添加相应的polyfill。
  • 可维护性:代码书写简洁,避免冗余(如重复代码封装为函数/组件);注释清晰,便于后续维护和他人理解。
  • 一致性:项目内所有代码严格遵循本规范,团队成员需统一认知;新增规范需团队讨论确认后补充,避免个人风格差异导致的代码混乱。
  • 废弃代码:禁止保留无用代码(如注释掉的代码、未使用的变量/函数/组件),提交代码前删除废弃内容,保持代码整洁。
相关推荐
Ruihong2 小时前
Vue 迁移 React 实战:VuReact 一键自动化转换方案
前端·vue.js
烟话62 小时前
vue3响应式基础
前端·javascript·vue.js
英俊潇洒美少年2 小时前
Vue Hook 与 React Hook 全面解析:区别、用法、实战及避坑指南
前端·vue.js·react.js
踩着两条虫3 小时前
VTJ.PRO 发布 v2.3.6:开放共享模版、优化发布流程,低代码开发体验再升级
vue.js·低代码·ai编程
ldybk3 小时前
教学vue
前端·javascript·vue.js
还是大剑师兰特3 小时前
Pinia介绍及Vue3配置示例
前端·javascript·vue.js
还是大剑师兰特3 小时前
Vue3 Mixin 与 Vue2 Mixin 核心区别
前端·javascript·vue.js
freeWayWalker3 小时前
Vue通用缩放容器
前端·javascript·vue.js
Hello--_--World4 小时前
VUE:逻辑复用
前端·javascript·vue.js