Vue 规范
vue 项目规范以 Vue 官方规范 中的 A、B、C 规范为基础,并根据实际项目特点略作调整,故应结合两者来执行规范。
重点强调
1、组件
(1)组件名
组件名应该始终是多个单词组成(大于等于 2),且命名规范为 PascalCase 格式,避免和 HTML 元素名称冲突。
// components/HeaderComponent.vue
export default {
name: 'HeaderComponent',
// ...
}
(2)组件文件名
组件文件名为 PascalCase 格式。如不指定组件名改组件会默认以文件名作为组件名称。
components/
|- MyComponents.vue
(3)组件文件夹名称和默认导出
一个组件可以被拆分成多个组件编写的应该建立目录并且建立 index.js 导出对象。禁止使用 index.vue 做默认导出。
components/
|- MyComponent/
|----index.js
|------MyComponent.vue
|------MyComponentList.vue
|------MyComponentListItem.vue
// index.js
import MyComponents from './MyComponent'
// 使用index.js作为默认导出
export default MyComponent
2、Template
(1)在 Template 模版中使用组件,应使用 烤串 kebab-case 模式
<div>
<my-component></my-component>
</div>
(2)Template 中每行写一个属性元素,指令都使用缩写形式
指令推荐都使用缩写形式,(用 : 表示 v-bind: 、用 @ 表示 v-on: 和用 # 表示 v-slot:)
<template class="area-wrap">
<a-select
:value="showVal"
:disabled="isDisabled"
:allowClear="allowClear"
:mode="mode"
:defaultActiveFirstOption="false"
:showArrow="false"
:filterOption="false"
@search="onSearch"
@change="onChange"
placeholder="请输入关键字检索"
notFoundContent="请输入"
showSearch
labelInValue
>
<a-select-option v-for="d in areaListData" :key="d.value">
{{ d.fullName ? d.fullName : d.name }}
</a-select-option>
</a-select>
</template>
(3) Template 属性元素书写顺序
指令 -> 属性 -> 事件 -> class -> style -> html 属性 -> bool 值属性
(4) 标签顺序保持一致
单文件组件应该总是让标签顺序保持为
<template></template>
<script></script>
<style></style>
3、Script
标签内部结构顺序
<script>
export default {
name: ,
components:,
directives:,
filters:,
mixins:,
props:,
data,
// 所有生命周期
created() {},
methods: {},
computed: {},
watch: {}
}
</script>
4、Style
因为默认使用 ESLint 进行 Vue 文件格式化,所以会丧失对 style 内样式格式化的功能
故每个 Vue 组件在编写样式时应使用 src 引用方式使用样式,样式文件使用更强力的 stylelint 进行校验和格式化操作
<style lang="less" src="./login.less" scoped>
5、Data
(1) 组件的 data 必须是一个函数
不用方法返回对象的多个子组件之间会互相影响
export default {
return {
name: 'foo',
list: ['banana','apple']
}
}
(2) data 初始化时可使用 props 值做初始化
export default {
props: {
userData: Object,
},
data() {
return {
name: this.userData.name,
}
},
}
6、Props
Props 定义应该尽量详细
- 使用 camelCase 驼峰命名
- 指定类型
- 加上注释,表明其含义
- 没有 required 就要加 default 默认值,默认值是引用类型的需要使用函数返回新对象
- 如果有业务需要,加上 validator 验证
以上内容为强制内容,非自愿
export default {
props: {
// 组件状态,用于控制组件的颜色
status: {
type: String,
required: true,
validator: function (value) {
return [
'success',
'info',
'error'
].indexOf(value) !== -1
}
},
// 用户级别,用于显示皇冠个数
userLevel:{
type: String,
required: true
}
}
}
7、Methods
(1) 声明 methods 无需使用 function 关键字
export default {
methods: {
yourMethod(arg1, arg2) {},
},
}
(2) methods 默认上下文是 Vue 实例对象无需使用箭头函数
(3) methods 绑定原生事件无需使用.bind(this)处理
export default {
mounted() {
this.$nextTick(() => {
window.addEventListener('resize', this.handleResize)
})
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResize)
},
methods: {
handleResize() {},
},
}
8、Computed
使用 Computed 替换模版中的条件判断
<template>
<div>
<!-- Bad -->
<template v-for="item in list">
<p v-if="item.name === 'foo'" key="item.name"></p>
</template>
<!-- Good -->
<template v-for="item in fooList">
<p key="item.name"></p>
</template>
</div>
</template>
<script>
export default {
data() {
return {
list: [{name: 'foo'}, {name: 'bar'}]
}
},
computed() {
fooList() {
return this.list.filter(item => item.name === 'foo')
}
}
}
</script>
9、操作 DOM
(1)使用 ref 属性指定 DOM 引用,禁止使用 document.getElementId 一类的查询选择器
(2)Vue 在生命周期中、更新数据后操作实际 DOM 必须使用$nextTick 函数,禁止使用 setTimeout
<template>
<div ref="dom" @click="handleClick">
{{ text }}
</div>
</template>
<script>
export default {
data() {
return {
text: 'blue'
}
},
mounted() {
this.$nextTick(() => {
console.log(this.$refs.dom.textContent)
}),
},
methods: {
handleClick() {
this.color = 'red'
console.log(this.$refs.dom.textContent)
this.$nextTick(() => {
console.log(this.$refs.dom.textContent)
})
}
}
}
</script>
10、事件解绑定与定时器清理
组件对 window,document,实际 DOM 等对象进行事件绑定的要在组件卸载时解绑定事件
<template>
<div ref="echart"></div>
</template>
<script>
import eCharts from 'echarts'
export default {
data() {
return {
eChartInstance: null,
timer: null,
}
},
mounted() {
this.$nextTick(() => {
this.timer = setInterval(() => {
console.log(this.timer)
}, 5000)
this.eChartInstance = eCharts.init({})
window.addEventListener('resize', this.handleResize)
// 与beforeDestroy功能相同
this.$once('hook:beforeDestroy', () => {
clearInterval(this.timer)
this.eChartInstance.dispose() // 释放图表实例
window.removeEventListener('resize', this.handleResize)
})
})
},
beforeDestroy() {
clearInterval(this.timer)
this.eChartInstance.dispose() // 释放图表实例
window.removeEventListener('resize', this.handleResize)
},
methods: {
handleResize() {
this.eChartInstance.resize()
},
},
}
</script>
Vue Router 规范
- 路由名称需全局唯一,路由名称需要视图层全链路 PascalCase 命名
- 路由跳转使用 name 参数跳转
- 路由传参数据量大时使用 params 传递
Vuex 规范
- 非必要数据不要放到 store 中
- 模块多的开启 namespace
- store 更新操作异步的应使用 action
项目目录规范
目录和静态资源使用烤串 kebab-case 命名法
功能文件使用小驼峰 camelCase 命名法
Vue 组件相关的文件和目录使用大驼峰 PascalCase 命名法
api 目录
- api 中的方法名要按照动词+名词的命名形式来
- api 中的每个方法要添加注释,描述清楚入参出参格式
- api 中的每个方法都直接返回 Promise 对象
import request from '@/utils/request'
import store from '@/store'
/*
* 获取字典
* @type {{key:string, value: string}} dict
* @param {string} 类型
* @returns {dict[]}
*/
export function doGetDict(type) {
return request.post('/management_cockpit/share/getAllBaseDefine', {
requestParams: {
procedure: { p_def_type: '' },
sid: store.getters.sid,
},
})
}
assets 目录
assets 为静态资源,里面存放 images, icons,fonts 等静态资源,静态资源命名格式为 kebab-case
|assets
|-- icons
| |-- logo.svg
|-- images
| |-- background-color.png
| |-- upload-header.png
|-- fonts
components 目录
此目录存放全局通用组件,应按照组件进行目录划分,目录命名为 PascalCase,组件命名规则也为 PascalCase
|components
|-- AreaList.vue
|-- Particles
| |-- index.js
| |-- particles.json
| |-- Particles.vue
|-- Echarts
| |-- index.js
| |-- Bar
| | |-- index.js
| | |-- Bar.vue
router 与 store 目录
这两个目录一定要将业务进行拆分,不能放到一个 js 文件里
views 目录
views 目录内 Vue 组件要使用 PascalCase 命名