Vue CLI 最佳实践与代码规范建议
一、Vue CLI 基础概述
Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统。它提供了一个交互式的项目脚手架,用于快速搭建新项目,还包含了丰富的插件生态,能方便地进行各种功能扩展,如添加路由、状态管理等。
1.1 安装与初始化项目
要使用 Vue CLI,首先需要安装它。在已经安装了 Node.js 的环境下,通过 npm 或 yarn 进行全局安装:
npm install -g @vue/cli
# 或者使用 yarn
yarn global add @vue/cli
安装完成后,使用 vue create
命令来初始化一个新项目。例如,创建一个名为 my - project
的项目:
vue create my - project
在初始化过程中,Vue CLI 会提供一系列的选项,如选择 Vue 的版本(2.x 或 3.x)、是否安装路由、状态管理等。
1.2 项目结构剖析
一个通过 Vue CLI 创建的典型项目结构如下:
my - project
├── public
│ ├── favicon.ico
│ └── index.html
├── src
│ ├── assets
│ │ └── logo.png
│ ├── components
│ │ └── HelloWorld.vue
│ ├── App.vue
│ ├── main.js
│ ├── router
│ │ └── index.js
│ └── store
│ └── index.js
├── babel.config.js
├── package.json
├── README.md
└── vue.config.js
- public 目录:包含了在构建过程中不会被处理的静态资源。
index.html
是项目的入口 HTML 文件,所有打包后的 JavaScript 和 CSS 文件会被注入到这个 HTML 文件中。 - src 目录:这是项目的主要源代码目录。
assets
用于存放静态资源,如图片、样式文件等;components
存放可复用的 Vue 组件;App.vue
是整个应用的根组件;main.js
是项目的入口 JavaScript 文件,用于创建 Vue 实例并挂载到 DOM 元素上;router
目录管理路由配置;store
目录用于 Vuex 的状态管理配置。 - babel.config.js:Babel 配置文件,用于将 ES6+ 语法转换为浏览器能识别的语法。
- package.json:项目的依赖管理文件,记录了项目所依赖的各种包及其版本信息,同时还包含了一些脚本命令,如
npm run serve
用于启动开发服务器,npm run build
用于打包项目。 - README.md:项目的说明文档,用于向其他开发者介绍项目的功能、使用方法等。
- vue.config.js:Vue CLI 的配置文件,可以在其中自定义一些构建选项,如修改输出目录、配置代理等。
二、Vue CLI 最佳实践
2.1 构建配置优化
在 vue.config.js
文件中,可以对项目的构建进行各种优化配置。
2.1.1 生产环境优化
- 压缩代码:Vue CLI 默认会在生产环境下压缩 JavaScript 和 CSS 代码。但对于一些较大的项目,可以进一步优化压缩配置。例如,使用
terser - webpack - plugin
来优化 JavaScript 压缩,在vue.config.js
中配置如下:
const TerserPlugin = require('terser - webpack - plugin');
module.exports = {
chainWebpack: config => {
config.optimization.minimize(true);
config.optimization.minimizer('terser').use(TerserPlugin, [{
parallel: true,
terserOptions: {
compress: {
drop_console: true // 生产环境移除 console.log
}
}
}]);
}
};
- 代码分割:为了避免打包后的文件过大,影响加载性能,可以使用代码分割。Vue CLI 内置了对
splitChunks
的支持。在vue.config.js
中配置如下:
module.exports = {
chainWebpack: config => {
config.optimization.splitChunks({
chunks: 'all',
minSize: 30000,
minChunks: 1,
automaticNameDelimiter: '~',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'chunk - vendors',
priority: -10
},
common: {
name: 'chunk - common',
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
});
}
};
这样配置后,会将来自 node_modules
的代码和项目中多次引用的公共代码分别打包成单独的文件,在页面加载时可以并行加载这些文件,提高加载速度。
2.1.2 开发环境优化
- 代理配置:在开发过程中,前端应用通常需要与后端 API 进行交互。由于浏览器的同源策略限制,在开发环境下会遇到跨域问题。可以通过 Vue CLI 的代理功能来解决。在
vue.config.js
中配置如下:
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000', // 后端 API 地址
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
};
这样,当前端应用向 /api
开头的地址发送请求时,会被代理到 http://localhost:3000
,从而解决跨域问题。
2.2 插件与工具的合理使用
Vue CLI 拥有丰富的插件生态,可以通过 vue add
命令来安装插件。
2.2.1 Vue Router
Vue Router 是 Vue.js 官方的路由管理器。通过 vue add router
命令可以方便地将其添加到项目中。在安装完成后,会在 src/router
目录下生成路由配置文件 index.js
。例如,配置一个简单的路由:
import Vue from 'vue';
import Router from 'vue - router';
import Home from '@/views/Home.vue';
import About from '@/views/About.vue';
Vue.use(Router);
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
}
]
});
在 App.vue
中使用路由:
<template>
<div id="app">
<router - link to="/">Home</router - link>
<router - link to="/about">About</router - link>
<router - view></router - view>
</div>
</template>
<script>
export default {
name: 'App'
};
</script>
<style>
/* 省略样式 */
</style>
2.2.2 Vuex
Vuex 是 Vue.js 应用程序的状态管理模式。通过 vue add vuex
命令安装后,会在 src/store
目录下生成 index.js
文件。例如,创建一个简单的 Vuex 状态管理:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('increment');
}, 1000);
}
},
getters: {
doubleCount(state) {
return state.count * 2;
}
}
});
在组件中使用 Vuex:
<template>
<div>
<p>Count: {{ $store.state.count }}</p>
<p>Double Count: {{ $store.getters.doubleCount }}</p>
<button @click="$store.commit('increment')">Increment</button>
<button @click="$store.dispatch('incrementAsync')">Increment Async</button>
</div>
</template>
<script>
export default {
name: 'Counter'
};
</script>
<style>
/* 省略样式 */
</style>
2.2.3 ESLint 与 Prettier
ESLint 是一个用于识别和报告 JavaScript 代码中模式问题的工具,Prettier 是一个代码格式化工具。通过 vue add eslint
命令可以将 ESLint 添加到项目中,并根据需要选择相关的配置选项,如是否使用 Airbnb、Standard 等风格的规则。
为了使 ESLint 和 Prettier 协同工作,需要进行一些额外的配置。在项目根目录下创建 .prettierrc.js
文件,配置 Prettier 的规则:
module.exports = {
semi: true,
singleQuote: true,
trailingComma: 'es5'
};
在 .eslintrc.js
文件中,添加如下配置,使 ESLint 能够识别 Prettier 的规则:
module.exports = {
// 省略其他配置
rules: {
// 让 ESLint 忽略 Prettier 已经处理的规则
'prettier/prettier': 'error'
}
};
这样,在开发过程中,通过 npm run lint
命令可以同时检查代码是否符合 ESLint 和 Prettier 的规则,保持代码风格的一致性。
2.3 多环境配置
在实际开发中,通常需要区分开发环境、测试环境和生产环境,不同环境可能有不同的 API 地址、服务器配置等。Vue CLI 支持通过 .env
文件来进行多环境配置。
2.3.1 环境文件命名规则
.env
:所有环境都加载的基础配置文件。.env.development
:开发环境下加载的配置文件。.env.test
:测试环境下加载的配置文件。.env.production
:生产环境下加载的配置文件。
2.3.2 配置示例
假设在不同环境下有不同的 API 地址,在 .env.development
文件中配置:
VUE_APP_API_URL=http://localhost:3000/api
在 .env.production
文件中配置:
VUE_APP_API_URL=https://production - server.com/api
在项目代码中,可以通过 process.env.VUE_APP_API_URL
来获取相应环境的 API 地址。例如,在一个 API 服务的封装文件中:
import axios from 'axios';
const api = axios.create({
baseURL: process.env.VUE_APP_API_URL
});
export default api;
三、Vue 代码规范建议
3.1 组件命名规范
- 文件名命名:组件文件名应该采用 PascalCase 命名方式,即首字母大写,每个单词的首字母也大写。例如,
MyComponent.vue
。这样命名的好处是在文件系统中易于识别,并且与 Vue 组件的注册和使用方式相匹配。 - 组件注册命名:在 Vue 组件中,无论是全局注册还是局部注册,组件名同样应使用 PascalCase 命名。例如:
// 全局注册
import Vue from 'vue';
import MyComponent from './components/MyComponent.vue';
Vue.component('MyComponent', MyComponent);
// 局部注册
export default {
components: {
MyComponent
}
};
- 避免使用保留字:组件名应避免使用 JavaScript 的保留字,如
if
、for
、function
等,以免在开发过程中出现语法错误或混淆。
3.2 模板语法规范
- 缩进与换行:在模板中,使用 2 个空格进行缩进,以保持代码的整洁和可读性。每个 HTML 标签尽量单独占一行,特别是对于复杂的组件结构。例如:
<template>
<div class="container">
<h1>{{ title }}</h1>
<ul>
<li v - for="(item, index) in items" :key="index">{{ item }}</li>
</ul>
</div>
</template>
- 指令使用规范:
- v - bind:当绑定的属性值是一个变量时,可以省略
v - bind
的简写形式:
。例如,:src="imageSrc"
等价于v - bind:src="imageSrc"
。但当绑定的值是一个复杂表达式时,建议使用完整形式,以提高可读性。例如,v - bind:class="{'active': isActive, 'disabled': isDisabled}"
。 - v - on:同样,
v - on
可以简写为@
。在绑定事件处理函数时,尽量使用方法名而不是内联表达式。例如:
- v - bind:当绑定的属性值是一个变量时,可以省略
<button @click="handleClick">Click Me</button>
export default {
methods: {
handleClick() {
// 处理逻辑
}
}
};
- **v - if 和 v - for**:避免在同一元素上同时使用 `v - if` 和 `v - for`。因为 `v - for` 的优先级高于 `v - if`,会导致不必要的计算。如果确实需要根据条件渲染列表,可以将 `v - if` 放在父元素上,或者使用计算属性过滤列表。例如:
<!-- 不推荐 -->
<li v - for="item in items" v - if="item.isVisible">{{ item.name }}</li>
<!-- 推荐方式一 -->
<ul v - if="filteredItems.length > 0">
<li v - for="item in filteredItems" :key="item.id">{{ item.name }}</li>
</ul>
<!-- 推荐方式二 -->
<ul>
<li v - for="item in getVisibleItems" :key="item.id">{{ item.name }}</li>
</ul>
export default {
data() {
return {
items: [
{ id: 1, name: 'Item 1', isVisible: true },
{ id: 2, name: 'Item 2', isVisible: false }
]
};
},
computed: {
filteredItems() {
return this.items.filter(item => item.isVisible);
},
getVisibleItems() {
return this.items.filter(item => item.isVisible);
}
}
};
3.3 样式规范
- 组件内样式:在 Vue 组件中,推荐使用
<style scoped>
来定义组件内的样式。这样可以确保样式只作用于当前组件,避免样式冲突。例如:
<template>
<div class="my - component">
<h1>My Component</h1>
</div>
</template>
<script>
export default {
name: 'MyComponent'
};
</script>
<style scoped>
.my - component {
background - color: lightblue;
}
</style>
- 全局样式:如果需要定义全局样式,可以在
src/assets
目录下创建一个styles
文件夹,在其中创建global.css
文件来存放全局样式。然后在main.js
中引入:
import Vue from 'vue';
import App from './App.vue';
import './assets/styles/global.css';
Vue.config.productionTip = false;
new Vue({
render: h => h(App)
}).$mount('#app');
- CSS 命名规范:采用 BEM(Block - Element - Modifier)命名规范。例如,一个按钮组件的样式命名可以如下:
/* 按钮块 */
.button {
padding: 10px 20px;
border: none;
background - color: blue;
color: white;
}
/* 按钮上的图标元素 */
.button__icon {
margin - right: 5px;
}
/* 按钮的禁用状态修饰符 */
.button--disabled {
background - color: gray;
cursor: not - allowed;
}
3.4 代码注释规范
- 组件注释:在每个 Vue 组件的开头,应该添加注释来描述组件的功能、使用方法、props 说明等。例如:
<template>
<!-- 省略模板内容 -->
</template>
<script>
/**
* @description 这是一个用户信息展示组件
* @props {string} name - 用户姓名
* @props {number} age - 用户年龄
* @example <UserInfo name="John" age="30" />
*/
export default {
name: 'UserInfo',
props: {
name: {
type: String,
required: true
},
age: {
type: Number,
required: true
}
}
};
</script>
<style scoped>
/* 省略样式 */
</style>
- 方法注释:对于组件中的方法,也应该添加注释说明方法的功能、参数和返回值。例如:
export default {
methods: {
/**
* 计算两个数的和
* @param {number} num1 - 第一个数
* @param {number} num2 - 第二个数
* @returns {number} 两数之和
*/
addNumbers(num1, num2) {
return num1 + num2;
}
}
};
- 逻辑注释:在代码逻辑较为复杂的地方,添加注释来解释代码的执行逻辑。例如:
// 过滤出年龄大于 18 岁的用户
const adults = users.filter(user => user.age > 18);
3.5 项目目录结构规范
- 按功能模块划分:对于较大的项目,建议按功能模块划分目录。例如,一个电商项目可以有如下目录结构:
src
├── components
│ ├── common
│ │ ├── Button.vue
│ │ └── Input.vue
│ └── product
│ ├── ProductList.vue
│ └── ProductDetail.vue
├── views
│ ├── home
│ │ └── Home.vue
│ ├── product
│ │ ├── ProductList.vue
│ │ └── ProductDetail.vue
│ └── cart
│ └── Cart.vue
├── router
│ └── index.js
├── store
│ └── index.js
├── assets
│ ├── images
│ │ └── logo.png
│ └── styles
│ └── global.css
├── main.js
这样的结构使得项目的功能模块清晰,易于维护和扩展。
- 避免过深的目录嵌套:尽量避免目录嵌套过深,一般不超过 3 层。如果确实需要更细的划分,可以通过命名空间来区分,而不是一味地增加目录层级。例如,在
components
目录下,可以通过前缀来区分不同类型的组件,如ui - Button.vue
、feature - ProductList.vue
等。
3.6 数据管理规范
- data 函数返回对象:在 Vue 组件中,
data
必须是一个函数,并且返回一个对象。这样可以确保每个组件实例都有自己独立的数据副本,避免数据共享导致的问题。例如:
export default {
data() {
return {
count: 0
};
}
};
- 使用 computed 和 watch:合理使用计算属性
computed
和侦听器watch
。计算属性用于依赖响应式数据的复杂计算,并且具有缓存机制,只有依赖的数据发生变化时才会重新计算。例如:
export default {
data() {
return {
firstNumber: 10,
secondNumber: 20
};
},
computed: {
sum() {
return this.firstNumber + this.secondNumber;
}
}
};
侦听器用于监听数据的变化,并执行相应的操作。例如,监听一个输入框的值变化,进行实时搜索:
export default {
data() {
return {
searchText: ''
};
},
watch: {
searchText(newValue) {
// 根据 newValue 进行搜索操作
}
}
};
- Vuex 状态管理规范:在使用 Vuex 时,要遵循单向数据流原则。状态的修改应该通过
mutations
来进行,而异步操作应该封装在actions
中。例如:
// store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
user: null
},
mutations: {
setUser(state, user) {
state.user = user;
}
},
actions: {
async login({ commit }, credentials) {
const response = await axios.post('/api/login', credentials);
commit('setUser', response.data.user);
}
}
});
在组件中调用:
<template>
<div>
<button @click="loginUser">Login</button>
</div>
</template>
<script>
export default {
methods: {
loginUser() {
const credentials = { username: 'test', password: 'test' };
this.$store.dispatch('login', credentials);
}
}
};
</script>
<style scoped>
/* 省略样式 */
</style>
通过遵循以上 Vue CLI 最佳实践和代码规范建议,可以提高项目的开发效率、代码质量和可维护性,使 Vue 项目更加健壮和易于扩展。在实际开发中,团队成员应共同遵守这些规范,形成良好的开发习惯。