Tips:这个规范是公司要求我来制定的,希望看官们可以帮忙多提些意见~
关于业务代码数据规范
本项规范中,单词的命名均为驼峰形式
具有业务功能的按钮
对于具有一定业务功能的按钮,如 添加用户
删除用户
编辑用户
等,我们将用以 handle
开头,业务结尾的方式来命名
以下述情况为例:
按钮业务 | 命名 |
---|---|
添加用户 | handleUserAdd |
删除用户 | handleUserDel |
编辑用户 | handleUserEdit |
批量删除用户 | handleUserDelBatch |
导入用户Excel | importUserExcel |
导出用户Excel | exportUserExcel |
tips:在这里我们需要注意一种情况,那就是如果我们的方法名称和我们导入的接口名称一样,那么我们应该以改变导入的接口名称为第一操作方式
普通的命名方法
有意义的命名即可
搜索条件及表格数据的命名
这将会分为两种情况,第一情况是无重名情况,另一种情况是有重名的情况
无重名的情况
字段意义 | 命名 |
---|---|
搜索条件 | searchApi |
表格数据 | tableData |
树的数据 | treeData |
有重名情况
我们可以结合实际业务对每个条件进行命名
下面将会给出示例:
字段意义 | 命名 |
---|---|
搜索城市列表条件 | citySearchApi |
城市表格数据 | cityTableData |
城市的树形数据 | cityTreeData |
对于data中的数据规范
数据量不大
按如下方式
{
stringVariable: "",
nullVariable|numberVariable:null,
arrayVariable:[],
objectVariable:{},
arrayObjectVariable:[{},{}]
}
按具体的业务分组
{
//group1
stringVariable: "",
nullVariable|numberVariable:null,
arrayVariable:[],
objectVariable:{},
arrayObjectVariable:[{},{}]
//group2
stringVariable: "",
nullVariable|numberVariable:null,
arrayVariable:[],
objectVariable:{},
arrayObjectVariable:[{},{}]
}
书写方法注释的规范
需要为方法提供它的变量、以及作用的注释
/**
* @description: 方法作用
* @param {参数类型} 参数名称 //如果接收参数的话
* @param {参数类型} 参数名称
* @return {返回值类型} //如果有返回值的话
*/
接口api的书写规范
/**
* @func 接口名称
* @param params //params是放在request header 中的请求参数 ~可选
* @param data // data是放在request body 内的参数 ~可选
* @description 接口的描述
*/
export const getAuthUserList = (params,data) => {
return request({
url: '/auth/role/list', //接口请求的url
method: 'get', // 接口请求方式
params, //request header参数
data // request boyd参数
})
}
tips:对于同属于一个功能模块的接口请求,我们应该将它们放在同个js文件内,并封装成如上形式
接口api的使用规范
import { getAuthUserList } from '@/api/auth'
//.......省略的部分.....
async getuserList(){
try{
const res = await getAuthUserList()
//........
}catch{
// do something
}
}
Vuex的使用规范
对于经常会在页面中调用的state,需要在getter中暴露
代码规范
关于v-for的key
总是不建议直接使用index来作为当前列表的key,应当尽可能地选用其它具有唯一性的值作为key
关于v-if 与 v-show ,需要明确二者之间的区别
v-if 如果为false,则初始不会渲染,如果切换v-if的值,它总是会重新渲染 v-show 不管初始值为何,都会渲染,且切换值仅仅是切换display:none这一css 对于过于频繁切换显示与否,且不涉及到内容视图强制更新的场景,更加推荐使用v-show
关于v-once
对于某些仅需要渲染一次的内容,更加推荐使用v-once
**tips:**如果在v-for中使用了v-once,那么我们必须要为这个元素加上一个key
关于视图强制渲染
forceUpdate
//component.vue
export default {
methods:{
componentUpdate(){
this.$forceUpdate()
}
}
}
key
//component.vue
<template>
<component-child :key='componentChildKey'></component-child>
</template>
<script>
export default {
data(){
return {
componentChildKey:1
}
},
methods:{
upDateComponentChild(){
this.componentChildKey += 1
}
}
}
</script>
关于数据的处理
过滤掉我们不需要的字段
对于某些业务场景中,如果后端返回的数据有一些是我们用不到的,那么我们应该在接收到数据的时候使用map映射来对这个数据进行简单的处理
//.....
try{
const res = await getDates()
this.tableData = res.map(el => {
let {a,b,c} = el
return{a,b,c}
}}
}catrh{return}
//.....
处理不需要响应式变动的数据
对于这种数据,我们应该使用**Object.freeze()**将这个数据进行冻结,因为vue对于configurable属性为false的数据是不会注入依赖的
亦或者我们也可以使用其它方法,类似Object.preventExtensions的这种方法
数组或者对象中判断是否存在某一条件的某一值
对于数组
直接的找值,我们可以使用Array.includes 、Array.indexOf等
对于条件值,需要我们进行循环的,我们可以使用Array.some
对于对象
如果我们有同上面类似的需求,查找是否存在符合某一条件的字段~
那么我们可以先使用Object.entries来行到其自身的可以枚举属性,拉下来就是数组的活了~
关于Promise
对于异步的请求,我总是推荐将其放在try catch中进行书写,在上面已经有一段示例中用到了这种写法
对于复杂的if条件判断
如果一个if()中的判断条件达到了2条或者以上,亦或者这个判断条件会在这个代码块中多次用到,我们应当使用一个命名合理的变量将这个判断结果保存
关于 watch computed methods
首先,我们先明确它们的使用场景:
- watch
监听某一个数据,它会影响到多个数据或者当它变化时,我们需要进行大量的其它操作
- computed
它是依赖于其它数据进行变化的,亦或者此项数据的计算有着极大地性能消耗
- methods
业务场景:同时监听多个数据
<script>
export default(){
computed:{
handleChange(){
const {fileName,FolderName} = this.$props
}
},
watch:{
handleChange:{
handler:function(val,oldval){
//do somting
},
immediate:true
}
}
}
</script>
Css书写规范
命名语义化
不要使用表象和晦涩难懂的名称,以下是错误的示例
<div class='red'></div>
Tips:如果不是必要情况,请不使用id
顺序问题
我们书写css的属性时,应该尽可能地遵循以下顺序
1.位置属性(position, display, float, z-index等) 2.大小(width, height, padding, margin) 3.文字相关 4.背景相关(background, border等) 5.其他(animation, transition等)
回流与重绘问题
如果某一块的css可能会经常改变,那么我们需要考虑其回流与重绘造成的性能代价,我们使用transition、transform等来替代
关于transiton和transform,可以参见下文:
transform
值 | 描述 |
---|---|
none | 定义不进行转换。 |
matrix(n,n,n,n,n,n) | 定义 2D 转换,使用六个值的矩阵。 |
matrix3d(n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n) | 定义 3D 转换,使用 16 个值的 4x4 矩阵。 |
translate(x,y) | 定义 2D 转换。 |
translate3d(x,y,z) | 定义 3D 转换。 |
translateX(x) | 定义转换,只是用 X 轴的值。 |
translateY(y) | 定义转换,只是用 Y 轴的值。 |
translateZ(z) | 定义 3D 转换,只是用 Z 轴的值。 |
scale(x,y) | 定义 2D 缩放转换。 |
scale3d(x,y,z) | 定义 3D 缩放转换。 |
scaleX(x) | 通过设置 X 轴的值来定义缩放转换。 |
scaleY(y) | 通过设置 Y 轴的值来定义缩放转换。 |
scaleZ(z) | 通过设置 Z 轴的值来定义 3D 缩放转换。 |
rotate(angle) | 定义 2D 旋转,在参数中规定角度。 |
rotate3d(x,y,z,angle) | 定义 3D 旋转。 |
rotateX(angle) | 定义沿着 X 轴的 3D 旋转。 |
rotateY(angle) | 定义沿着 Y 轴的 3D 旋转。 |
rotateZ(angle) | 定义沿着 Z 轴的 3D 旋转。 |
skew(x-angle,y-angle) | 定义沿着 X 和 Y 轴的 2D 倾斜转换。 |
skewX(angle) | 定义沿着 X 轴的 2D 倾斜转换。 |
skewY(angle) | 定义沿着 Y 轴的 2D 倾斜转换。 |
perspective(n) | 为 3D 转换元素定义透视视图。 |
默认值: | none |
---|---|
继承性: | no |
版本: | CSS3 |
JavaScript 语法: | object.style.transform="rotate(7deg)" |
transtion
值 | 描述 |
---|---|
transtion-property | 规定设置过渡效果的 CSS 属性的名称。 |
transtion-duration | 规定完成过渡效果需要多少秒或毫秒。 |
transtion-timing-function | 规定速度效果的速度曲线。 |
transtion-delay | 定义过渡效果何时开始。 |
默认值: | all 0 ease 0 |
---|---|
继承性: | no |
版本: | CSS3 |
JavaScript 语法: | object.style.transition="width 2s" |
尽量避免使用标签名
尽量避免以下写法:
.app-header span{
}
推荐以下写法
.app-header>.name-title{
}
Css注释规范
/*
* 块状注释
*/
/* 单行注释文字 */
关于常规框架使用
路由
懒加载
首先,对于路由,我们要使用懒加载的方式
{
path: '/home',
name: 'home',
component: import(/* webpackChunkName: '你要设置的chunk的name' */ '../page/home')
}
权限
我们的系统内部的路由有两个部分,一部分是静态路由,一部分是动态路由
对于引入权限之后,需要接入动态路由的情况下,可以打开 src/store/modules/permission.js
拉到下面的 generateRoutes
这个action,切换注释区域
组件
单独的页面
我们的最外层我已经设置了一个class,如果不是需要,请不要单独再设置一个class来控制,具体的在APP.vue中~
懒加载
强调的是,对于象Modal的这种的组件,我们总是应该使用懒加载来加载它~
这里的 /* webpackChunkName: "[request]" */
中的 request
表示实际解析的文件名。
const PageFooter = () => import(/* webpackChunkName: "[request]" */'_c/PageFooter')
export default {
components: {
'page-footer':pageFooter
}
}
权限
只需要控制单个按钮的情况:
<template>
<div>
<el-Button v-permission:delete="roles">按钮</el-Button>
</div>
</template>
<script>
computed: {
hasSelected() {
return this.delUserList.length > 0
},
roles() {
return this.$route.meta.roles ? this.$route.meta.roles : []
}
},
</script>
控制条件渲染的情况
<template>
<div>
<div v-if='hasRole'>条件渲染区域</div>
</div>
</template>
<script>
computed: {
hasRole() {
const arr = ['add', 'edit', 'delete']
const hasRole = arr.some(el => {
return this.roles.some(e => e === el)
})
return hasRole
}
roles() {
return this.$route.meta.roles ? this.$route.meta.roles : []
}
},
</script>
SearchForm
这是一个表单搜索组件,目前只提供一些简单的功能,建议可以使用的 type 目前只有 : el-input
el-select
el-date-picker
需要注意的是,戴止我写完这偏文档为止,时间选择器在同一SearchForm中,有且仅能有一个~
使用方法我将在下面做出一个demo示例:
<template>
<div class="card-block">
<search-form :list="formList" :search-width="200" @change="initChange" />
</div>
</template>
<script>
const SearchForm = () => import('_c/SearchForm')
export default {
components: {
'search-form': SearchForm
},
data() {
return {
formList: [
{
name: 'name',
type: 'el-input',
value: '',
placeholder: '请输入姓名'
},
{
name: 'age',
type: 'el-select',
value: '',
placeholder: '请输入岁数',
children: {
type: 'el-option',
list: [{
value: '选项1',
label: '黄金糕',
title: '黄金糕'
},
{
value: '选项2',
label: '黄金糕2',
title: '黄金糕2'
}]
}
},
{
name: 'time',
type: 'el-date-picker',
//指定单个表单的宽度,如果不写,则会取上面的search-width,如果search-width也没有给,则是会取默认宽度180
width: 450
}
],
pageApi: {
Index: 1,
PageSize: 10
}
}
},
methods: {
initChange(date) {
// 全并查询条件
this.pageApi = Object.assign(this.pageApi, date)
console.log(this.pageApi)
}
}
}
</script>