在家办公的第47天,昨天上海单日确诊跌破1万了,虽然不知道数据真假,但起码有盼头了。
前言
代码的最终归宿都是屎山罢了,而一份适用于团队的代码规范,可以极大延缓屎山的堆积速度。当团队内所有人都严格遵循代码规范时,屎山代码也可以拥有极强的可读性和可扩展性,每个人都可以提前完成迭代任务,剩下的时间用来摸鱼啊不,用来全方位提升自己岂不是更爽。
文中部分标注了删除线的,代表eslint已开启了相关配置,vscode会自动做出提示。
本文在线 思维导图 地址
项目工程规范
上图是整体项目目录,对于有点经验的正常前端开发人员,讲道理看文件名字应该都能基本理清用途。所以对我们团队内部的项目工程规范来说,将着重于文件命名规范和存在位置。
1、项目文件命名统一使用短横线分隔
2、对于.vue文件要求使用关注点分离,对页面进行拆分
使用 vue-generate-component 插件,在控制台执行ovgc demo-page,将自动创建如下文件 插件地址 fork自 地址
无css样式时,删除scss文件,无单元测试时,删除spec文件。
3、针对所有项目中涉及到的请求,统一封装成服务,按照功能模块命名,放在src/api文件目录下
- 对于服务命名要求词尾统一加Serivce
- 统一在src / api / index.ts文件中 export
- 统一从 ‘@/api’ 下 import
4、公共的过滤器和指令放在src文件下对应的文件夹中,按功能进行命名,中间以短横线分隔,在index.ts文件中统一 export (在main.ts中会统一注册)
5、公共的mixin放在src/mixins中,按功能进行命名,中间以短横线分隔,特殊业务下的mixin可放在具体使用的位置,后缀加mixin用来做区分
6、特殊工具类放在src/utils文件夹下,公共工具类放在src/utils/index中
使用时,公共方法统一从 '@/utils’中 import
import { fuzzyQueryStr } from '@/utils';
而特殊工具类,从各自所属位置import
import { axiosRequest } from '@/utils/axios-request';
7、路由按照模块进行区分,放在src/router/modules文件夹中
8、vuex按照大模块进行拆分,放在src/store/modules文件夹中,另外仓储服务输出时,要求使用大驼峰命名,与一般的服务类进行区分。
export const PermissionModule = getModule(Permission);
9、i18n翻译文件,以资源对象进行分割,该对象所有相关的文案都放在该对象下,不允许有重复的文案出现
以项目为例,所有与项目相关的文案都放在project 对象内。
10、所有业务相关的页面存放在views文件夹下,按大模块建立对应的文件夹
js规范
1、命名
1.1、变量和方法名使用小驼峰命名,禁止使用短横线或下划线
1.2、对于复杂的事件回调处理,方法名前统一使用handle前缀,如果功能单一,可以酌情使用功能用途命名
// 单一功能
<button @click="goBack"> 返回上一页 </button>
// 复杂功能 - 需要对子组件emit的change事件做出响应
<xxx-page @change="handleXXXChange"></xxx-page>
1.3、一个好的命名,应该是能让别人一眼就看出用途的,所以请根据你的目的进行命名,如果转化为英文后名字过长,可酌情使用简写
2、注释
对于注释,我的理解是注释在于而精不在于多,注释并不是越多越全就越好,因为写注释会耗费部分时间,且后续逻辑出现变化,还需要对注释进行维护更新,如果只更新了逻辑而忘记更新注释,那将是毁灭性的灾难,后面其他人看到这段驴头不对马嘴的代码和注释,一头雾水还要根据git记录跑来问你,这会耗费更多的时间。
因此对于一部分不太复杂的逻辑,完全可以通过优秀的变量或方法命名,让人在阅读时迅速理解这段代码的用途。当你自己在写这块代码时,都觉得业务难易理解或代码难以组织时,请务必加上注释
2.1、对于逻辑较复杂的代码,首先应在复杂代码块初始位置,写出本段逻辑处理的目的,然后针对复杂点逐行写出逻辑处理原因
2.2、当写有注释的代码发生变化时,务必要检查对应的注释,并同步修改
2.3、对于代码行的注释使用双斜 // 即可,对于方法务必使用 /**/,并对出入参和出参做出注释
public checkProjectName(name: string, customerId: number, id?: number): Promise<boolean> {}
3、变量声明
3.1、禁止使用var,用let和const替代
对于数组和对象或其他引用类型,后续不影响引用地址的情况下,允许使用const定义
3.2、非必要情况下,不要定义临时变量
3.3、定义对象时,请使用对象属性值的简写方式
const job = 'FrontEnd'
const item = {
job: job
}
const item = {
job
}
3.4、变量不要进行链式赋值,会污染全局变量
(function example() {
let a = b = c = 1
}())
console.log(a)
console.log(b)
console.log(c)
(function example() {
let a = 1
let b = a
let c = a
}())
console.log(a)
console.log(b)
console.log(c)
3.5、不允许出现未被使用的变量
4、模块化
4.1、请使用标准的 ES6 模块语法 import 和 export
4.2、同个文件每个模块只允许 import 一次,有多个 import 请书写在一起
import foo from 'foo'
import { named1, named2 } from 'foo'
import foo, { named1, named2 } from 'foo'
5、function
5.1、禁止修改传入的参数
5.2、一个方法的参数不能超过三个,当你发现参数过多时,应考虑拆分方法
5.3、禁止声明无用参数
5.4、可能为空的参数必须放在最后面
5.5、 不要使用 arguments,使用 剩余运算符
function test () {
const args = Array.prototype.slice.call(arguments)
return args.join('')
}
function test (...args) {
return args.join('')
}
6、其他
6.1、句尾使用分号
6.2、拼接字符串时禁止使用+号,请使用模板字符串
6.3、判断时请使用( === )而非( == )
6.4、对象属性访问请使用obj.xxx,除非属性名是变量才允许使用obj[xxx]
6.5、尽量减少代码层级嵌套,当嵌套大于等于三层时,就该考虑优化代码逻辑了
if(xxx){
do something1;
} else {
do something2;
if(xxx) {
do something3;
} else {
do something4;
}
}
if(xxx){
do something1;
return;
}
do something2;
if(xxx) {
do something3;
return;
}
do something4;
6.6、优先使用promise,若非绝对必要,禁止使用回调函数
6.7、使用async和await语法糖时,必须使用try catch
ts规范
1、访问修饰符
1.1、在声明变量或方法时,针对该方法的目的,设置访问权限
使用方式参考 ts 官方文档
1.2、私有方法一般放在公有方法后面,属性声明放在公有方法前
public selectedRows: Array<ProjectList> = [];
private queryForm: Partial<ProjectListQuery> = {};
public created(): void {
}
private clearSelection(): void {
}
1.3、对于vue的prop,或inject,请使用readonly修饰
2、类型声明
2.1、类型声明文件后缀名为.d.ts,统一放在项目src/resource下面
2.2、类型统一使用大驼峰命名
2.3、要求以每个对象和具体功能为基础,建立该对象的相关操作的实体类,统一导出
以项目对象project为例,功能包含
- 列表页 ProjectList
- 分页查询条件检索 ProjectListQuery
- 新增、编辑 CreateProject,如果编辑只需要对少部分字段进行修改,则建立 UpdateProject
- 详情页展示 ProjectInfo
以上类型一般基于一个较为全面的基础类型,改造而来。ts提供了诸如使用Omit,Pick,Partial,Required关键字,对类型进行修改,从而获得一个新的类型。这样当字段发生变化时,只需使用vscode重构功能,对基础类型进行修改后,即可同步影响到所有相关的类型。
可根据实际情况,选择ProjectInfo或ProjectList作为基类,当都不满足条件时,可以选择声明ProjectBase类型抽取公共字段。
2.4、对于每个类型和属性声明,必须具有注释
2.5、对于数组的定义,使用泛型方式
const arr: number[] = [1, 2, 3];
const arr: Array<number> = [1, 2, 3];
3、function
3.1、必须具有返回类型
3.2、参数必须具有类型声明
3.3、必须具有访问修饰符
public xxx(): void {
do something;
}
protected xxx(): boolean {
return true;
}
private xxx(): string {
return 'xxxxxx';
}
public xxx(): 其他支持的类型 {
return 其他支持的类型
}
4、其他
4.1、若非必要,禁止使用any类型
4.2、枚举必须具有注释,且后缀名必须为Enum
枚举对应的i18n翻译,一般以枚举名,去掉Enum后缀,然后以小驼峰命名,例如ProjectStatusEnum ,代表项目状态枚举类
export enum ProjectStatusEnum {
new = 1,
....
}
i18n文案为
projectStatus: {
new: '新建',
...
}
vue
1、模板文件
1.1 、组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。
// bad
<el-button size="small" @click="detailsVisible = false">关闭</el-button>
// good
<el-button size="small" @click="close">关闭</el-button>
// bad
<span>{{ totalMoney * 2 }}</span>
// good
<span>{{ doubleMoney }}</span>
public close ():void {
this.detailsVisible = false
}
public get doubleMoney(): number {
return this.doubleMoney * 2
}
2、命名问题
2.1 、组件命名采用短横线命名法
2.2 、emit 事件单词之间使用 - 分隔,禁止使用驼峰
2.3 、组件传参时,标签上需要对使用了驼峰命名的prop,使用短横线命名
假如 B组件接收一个totalMoney,A组件传参时如下
// good
<b :totalMoney="123"></b>
// best
<b :total-money="123"></b>
// error
<b totalMoney="123"></b>
3、其他
3.1 、设置prop时,必须填写options
@Prop({ type: String, required: true })
public readonly msg!: string;
@Prop({ type: String, required: false, default:'' })
public readonly msg!: string;
css
1、命名
1.1、使用短横线进行class命名
2、其他
2.1、多页面都用到的公共样式,禁止复制粘贴,必须放在src/style/index.scss中
2.2、注释使用单行注释
注释内容第一个字符和最后一个字符都是一个空格字符,单独占一行,行与行之间相隔一行
.jdc{}
.jdc1{}
2.3、scss可复用属性尽量抽离为变量,易于统一维护
…未完待续
|