Appearance
代码规范
良好的代码规范是团队协作和项目维护的基础。本章将介绍 Vue.js 项目的代码风格最佳实践。
组件命名
组件文件名
组件文件名应该始终是单词大写开头 (PascalCase):
components/
├── MyComponent.vue
├── UserProfile.vue
└── NavigationMenu.vue组件名
在 JavaScript 中引用组件时使用 PascalCase:
javascript
import MyComponent from './MyComponent.vue'
import UserProfile from './UserProfile.vue'在模板中使用组件时,推荐使用 kebab-case:
vue
<template>
<my-component />
<user-profile />
</template>基础组件命名
基础组件(展示类的、无逻辑的或无状态的组件)应该全部以一个特定的前缀开头:
components/
├── BaseButton.vue
├── BaseTable.vue
├── BaseIcon.vue
├── AppButton.vue
├── AppTable.vue
└── AppIcon.vue单例组件命名
只应该拥有单个活跃实例的组件应该以 The 前缀命名:
components/
├── TheHeading.vue
├── TheSidebar.vue
└── TheFooter.vue紧密耦合的组件名
和父组件紧密耦合的子组件应该以父组件名作为前缀命名:
components/
├── TodoList.vue
├── TodoListItem.vue
├── TodoListItemButton.vue
├── UserProfileOptions.vue
└── UserProfileOptionsButton.vue组件结构
单文件组件的顶级元素顺序
单文件组件应该总是让顶级元素的顺序保持一致:
vue
<!-- 1. template -->
<template>
<div class="my-component">
<!-- 组件内容 -->
</div>
</template>
<!-- 2. script -->
<script>
export default {
name: 'MyComponent'
}
</script>
<!-- 3. style -->
<style scoped>
.my-component {
/* 样式 */
}
</style>组件选项顺序
组件选项应该按照以下顺序排列:
javascript
export default {
// 1. 全局感知 (要求在组件外的知识)
name: 'MyComponent',
// 2. 模板依赖 (模板内使用的资源)
components: {},
directives: {},
// 3. 组合 (向选项里合并属性)
extends: {},
mixins: [],
// 4. 接口 (组件的接口)
inheritAttrs: false,
props: {},
emits: [],
// 5. 组合式 API (使用组合式 API 的入口点)
setup() {},
// 6. 本地状态 (本地的响应式属性)
data() {},
computed: {},
// 7. 事件 (通过响应式事件触发的回调)
watch: {},
// 8. 生命周期钩子 (按照它们被调用的顺序)
beforeCreate() {},
created() {},
beforeMount() {},
mounted() {},
beforeUpdate() {},
updated() {},
activated() {},
deactivated() {},
beforeUnmount() {},
unmounted() {},
errorCaptured() {},
// 9. 非响应式的属性 (不依赖响应式系统的实例属性)
methods: {}
}Props 定义
详细的 Props 定义
Props 应该尽可能详细,至少需要指定其类型:
javascript
// 不好
props: ['status']
// 好
props: {
status: String
}
// 更好
props: {
status: {
type: String,
required: true,
validator(value) {
return ['syncing', 'synced', 'version-conflict', 'error'].includes(value)
}
}
}Prop 名大小写
在声明 prop 的时候,其命名应该始终使用 camelCase,而在模板和 JSX 中应该始终使用 kebab-case:
javascript
// JavaScript
props: {
greetingText: String
}vue
<!-- 模板 -->
<welcome-message greeting-text="hi" />模板规范
模板中的表达式
模板中应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法:
vue
<!-- 不好 -->
<template>
{{
fullName.split(' ').map((word) => {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}}
</template>
<!-- 好 -->
<template>
{{ normalizedFullName }}
</template>
<script>
computed: {
normalizedFullName() {
return this.fullName.split(' ')
.map(word => word[0].toUpperCase() + word.slice(1))
.join(' ')
}
}
</script>指令缩写
指令缩写应该要么都用要么都不用:
vue
<!-- 不好 -->
<input
v-bind:value="newTodoText"
:placeholder="newTodoInstructions"
>
<!-- 好 -->
<input
:value="newTodoText"
:placeholder="newTodoInstructions"
>
<!-- 好 -->
<input
v-bind:value="newTodoText"
v-bind:placeholder="newTodoInstructions"
>多个 attribute 的元素
多个 attribute 的元素应该分多行撰写,每个 attribute 一行:
vue
<!-- 不好 -->
<img src="https://vuejs.org/images/logo.png" alt="Vue Logo">
<!-- 好 -->
<img
src="https://vuejs.org/images/logo.png"
alt="Vue Logo"
>
<!-- 不好 -->
<MyComponent foo="a" bar="b" baz="c" />
<!-- 好 -->
<MyComponent
foo="a"
bar="b"
baz="c"
/>JavaScript 规范
变量命名
使用有意义的变量名:
javascript
// 不好
const d = new Date()
const u = user.name
const isV = user.isValid
// 好
const currentDate = new Date()
const userName = user.name
const isUserValid = user.isValid函数命名
函数名应该是动词或动词短语:
javascript
// 不好
function userData() {}
function userValidation() {}
// 好
function getUserData() {}
function validateUser() {}
function handleClick() {}
function fetchUserProfile() {}常量命名
常量使用全大写字母和下划线:
javascript
const API_BASE_URL = 'https://api.example.com'
const MAX_RETRY_COUNT = 3
const DEFAULT_TIMEOUT = 5000避免魔法数字
使用命名常量代替魔法数字:
javascript
// 不好
if (user.age >= 18) {
// ...
}
// 好
const LEGAL_AGE = 18
if (user.age >= LEGAL_AGE) {
// ...
}CSS 规范
作用域样式
为组件样式设置作用域:
vue
<style scoped>
.button {
border: none;
border-radius: 2px;
}
.button-close {
background-color: red;
}
</style>CSS 类命名
使用 kebab-case 命名 CSS 类:
css
/* 不好 */
.myComponent {}
.my_component {}
/* 好 */
.my-component {}
.user-profile {}BEM 命名规范
对于复杂组件,考虑使用 BEM 命名规范:
css
/* Block */
.card {}
/* Element */
.card__header {}
.card__body {}
.card__footer {}
/* Modifier */
.card--large {}
.card--highlighted {}
.card__header--centered {}注释规范
组件注释
为复杂组件添加注释:
vue
<template>
<!-- 用户头像,支持点击上传新头像 -->
<div class="user-avatar" @click="handleAvatarClick">
<img :src="avatarUrl" :alt="userName" />
</div>
</template>
<script>
/**
* 用户头像组件
*
* @description 显示用户头像,支持点击上传功能
* @author John Doe
* @since 1.0.0
*/
export default {
name: 'UserAvatar',
props: {
/**
* 用户名,用于 alt 属性
*/
userName: {
type: String,
required: true
},
/**
* 头像 URL
*/
avatarUrl: {
type: String,
default: '/default-avatar.png'
}
}
}
</script>函数注释
为复杂函数添加 JSDoc 注释:
javascript
/**
* 计算用户的年龄
*
* @param {string} birthDate - 出生日期 (YYYY-MM-DD 格式)
* @returns {number} 用户年龄
* @throws {Error} 当日期格式不正确时抛出错误
*
* @example
* const age = calculateAge('1990-01-01')
* console.log(age) // 33
*/
function calculateAge(birthDate) {
// 实现逻辑
}错误处理
统一错误处理
建立统一的错误处理机制:
javascript
// utils/errorHandler.js
export function handleError(error, context = '') {
console.error(`Error in ${context}:`, error)
// 发送错误到监控服务
if (process.env.NODE_ENV === 'production') {
// sendToErrorService(error, context)
}
}
// 在组件中使用
export default {
methods: {
async fetchUserData() {
try {
const data = await api.getUser()
this.userData = data
} catch (error) {
handleError(error, 'UserProfile.fetchUserData')
}
}
}
}代码格式化
ESLint 配置
使用 ESLint 保持代码风格一致:
javascript
// .eslintrc.js
module.exports = {
extends: [
'plugin:vue/vue3-essential',
'@vue/eslint-config-prettier'
],
rules: {
'vue/multi-word-component-names': 'error',
'vue/component-definition-name-casing': ['error', 'PascalCase'],
'vue/component-name-in-template-casing': ['error', 'kebab-case'],
'vue/prop-name-casing': ['error', 'camelCase']
}
}Prettier 配置
使用 Prettier 自动格式化代码:
json
{
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 80,
"bracketSpacing": true,
"arrowParens": "avoid"
}Git 提交规范
使用约定式提交规范:
bash
# 功能
git commit -m "feat: 添加用户头像上传功能"
# 修复
git commit -m "fix: 修复登录表单验证问题"
# 文档
git commit -m "docs: 更新 API 文档"
# 样式
git commit -m "style: 调整按钮样式"
# 重构
git commit -m "refactor: 重构用户服务模块"
# 测试
git commit -m "test: 添加用户注册测试用例"
# 构建
git commit -m "build: 更新 webpack 配置"