前端代码规范

规范的目的是为了编写高质量的代码,让你的团队成员每天得心情都是愉悦的,大家在一起是快乐的。

引自《阿里规约》的开头片段: ----现代软件架构的复杂性需要协同开发完成,如何高效地协同呢?无规矩不成方圆,无规范难 以协同,比如,制订交通法规表面上是要限制行车权,实际上是保障公众的人身安全,试想如果 没有限速,没有红绿灯,谁还敢上路行驶。对软件来说,适当的规范和标准绝不是消灭代码内容 的创造性、优雅性,而是限制过度个性化,以一种普遍认可的统一方式一起做事,提升协作效率, 降低沟通成本。代码的字里行间流淌的是软件系统的血液,质量的提升是尽可能少踩坑,杜绝踩 重复的坑,切实提升系统稳定性,码出质量。

一.编程规约

(一) 命名规范

1.1.1 项目命名

全部采用小写方式,以中线分隔。

1
2
3
正例:mall-management-system

反例:mall_management-system / mallManagementSystem

1.1.2 文件目录命名

所有文件夹使用 PascalCase (大驼峰式) 命名法 此处文件夹指代 开发人员自己新增文件夹,系统内建文件夹除外。如:src pages components 等文件夹

1
2
3
正例:UserLogin

反例:user-login /userLogin

1.1.3 组件文件命名

使用 PascalCase (大驼峰式) 命名法

  1. 定义class组件的时候,必须采取大驼峰式命名法。例: AddItem 。
  2. 当需要引用组件的时候,名字要与组件相同,并且采取大驼峰式命名法。
1
2
3
4
5
6
7
8
9
// Not well
import notFound from "@/components/NotFound";
// Better
import NotFound from "@/components/NotFound";

// Not Well
const notFound = lazy(() => import('@/components/NotFound'));
// Better
const NotFound = lazy(() => import('@/components/NotFound'));

1.1.4 JSON、PNG 等文件命名

全部采用小写方式, 以中划线分隔。

1
2
3
正例: company-logo.png / data.json

反例: UserManagement.jpg

1.1.5 命名严谨性

代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。

说明:正确的 英文拼写和语法可以让阅读者易于理解,避免歧义。注意,即使纯拼音命名方式也要避免采用

1
2
3
4
5
正例:henan / luoyang / rmb 等国际通用的名称,可视同英文 

反例:DaZhePromotion [打折] / getPingfenByName() [评分] / int 某变量 = 3 杜绝完全不规范的缩写,避免望文不知义:

反例:AbstractClass “缩写”命名成 AbsClass;condition “缩写”命名成 condi,此类随意缩写严重 降低了代码的可阅读性。

(二) 目录结构规范

1.2.1 React 目录结构

  1. 公共组件统一写在src/components下。
  2. 功能模块代码存放在src/pages文件夹,一个功能模块对应一个文件夹,功能模块文件夹里应有index.tsx、service.ts、index.module.scss/index.module.less 三个文件和components文件夹。文件意义如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
src
├── components # 公共组件
│ ├── BaseInfo
│ └── NotFound
├── config # 配置文件
│ └── breadcrumbConfig.ts # 面包屑
├── layouts # 页面布局
│ └── BasicLayout
├── pages # 功能模块代码
│ └── UserLogin
│ ├──components # 功能模块组件
│ ├──index.tsx # 功能模块入口
│ ├──index.modules.less # 功能模块样式
│ └──service.ts # 功能模块接口存放文件
├── models # 全局数据状态
│ ├── menu.ts
│ ├── userProfile.ts
├── utils # 全局公用方法
│ └── request.ts
├── global.less # 公共样式
├── app.tsx # 项目入口
└── router.ts # 路由配置文件

1.2.2 Vue 目录结构

  1. 公共组件统一写在src/components下。
  2. 功能模块代码存放在src/views文件夹,一个功能模块对应一个文件夹,功能模块文件夹里应有index.vue、service.js、index.module.scss/index.module.less 三个文件和components文件夹。文件意义如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
├── public                     						# 静态资源
│ │── favicon.ico # favicon图标
│ └── index.html # html模板
├── src # 源代码
│ ├── assets # 主题 字体等静态资源
│ ├── components # 全局公用组件
│ ├── routes # 路由
│ ├── utils # 全局公用方法
│ │ └── request.js # 封装ajax方法
│ ├── views # views 所有页面
│ │ └── UserLogin
│ │ ├──components # 功能模块组件
│ │ ├──index.vue # 功能模块入口
│ │ ├──index.modules.less # 功能模块样式
│ │ └──service.js # 功能模块接口存放文件
│ ├── vuex # vue状态管理
│ ├── App.vue # 入口页面
│ └── main.js # 入口文件 加载组件 初始化等
├── .eslintrc.js # eslint 配置项
├── vue.config.js # vue-cli 配置
└── package.json # package.json

(三) HTML 规范

1.3.1 HTML 类型

推荐使用 HTML5 的文档类型申明

建议使用 text/html 格式的 HTML。避免使用 XHTML。XHTML 以及它的属性,比如 application/xhtml+xml 在浏览器中的应用支持与优化空间都十分有限。

  • 规定字符编码
  • IE 兼容模式
  • 规定字符编码
  • doctype 大写 正例:
1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta charset="UTF-8" />
<title>Page title</title>
</head>
<body>
<img src="images/company-logo.png" alt="Company">
</body>
</html>

1.3.2 语义化标签

HTML5 中新增很多语义化标签,所以优先使用语义化标签,避免一个页面都是 div 或者 p 标 签。

1
2
3
4
5
6
7
8
正例:
<header></header>
<footer></footer>

反例:
<div>
<p></p>
</div>

1.3.3 标签属性顺序

属性应该按照特定的顺序出现以保证易读性

  • class
  • id
  • name
  • data-*
  • src, for, type, href, value , max-length, max, min, pattern
  • placeholder, title, alt
  • aria-*, role
  • required, readonly, disabled
1
2
3
<a class="..." id="..." data-modal="toggle" href="#">Example link</a>
<input class="form-control" type="text">
<img src="..." alt="...">

1.3.4 标签属性引号

使用双引号(" ") 而不是单引号(' ')

1
2
3
正例:<div class=”box”></div>

反例:<div class='box'></div>

(四) CSS 规范

1.4.1 命名

ID 和 class 使用小写字母,以中划线分隔命名法

ID 和 class 的名称总是使用可以反应元素目的和用途的名称,或其他通用的名称,代替表象和晦涩难懂的名称。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
不推荐: 

.fw-800 {
font-weight: 800;
}
.red {
color: red;
}

推荐:

.heavy {
font-weight: 800;
}
.important {
color: red;
}

1.4.2 选择器

  1. css 选择器中避免使用标签名 从结构、表现、行为分离的原则来看,尽量避免 css 中出现 HTML 标签,并且在 css 选择器中出现标签名会存在潜在的问题
  2. 使用直接子选择器 很多前端开发人员写选择器链的时候不使用 直接子选择器(注:直接子选择器和后代选择器的 区别)。有时,这可能会导致疼痛的设计问题并且有时候可能会很耗性能。然而,在任何情况下, 这是一个非常不好的做法。如果你不写很通用的,需要匹配到 DOM 末端的选择器, 你应该总 是考虑直接子选择器。
1
2
3
不推荐: .content .title { font-size: 2rem; } 

推荐: .content > .title { font-size: 2rem; }

1.4.3 使用缩写属性且独占一行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
不推荐: 
border-top-style: none;
font-family: palatino, georgia, serif;
font-size: 100%;
line-height: 1.6;
padding-bottom: 2em;
padding-left: 1em;
padding-right: 1em;
padding-top: 0;

推荐:
border-top: 0;
font: 100%/1.6 palatino, georgia, serif;
padding: 0 1em 2em;

不推荐:
button {
width: 100px; height: 50px;
color: #fff; background: #00a0e9;
}

推荐:
button {
width: 100px;
height: 50px;
color: #fff;
background: #00a0e9;
}

1.4.4 避免使用 ID 选择器及全局标签选择器

ID 选择器及全局标签选择器可能污染全局样式

1
2
3
4
5
6
7
8
9
10
11
不推荐: 
#header {
padding-bottom: 0px;
margin: 0em;
}

推荐:
.header {
padding-bottom: 0px;
margin: 0em;
}

1.4.5 书写顺序

遵循:布局定位属性 --> 自身属性 --> 文本属性做分组,组之间需要有一个空行

建议:自身属性 按照盒模型由内而外或者由外而内顺序书写

布局定位 自身属性 文本属性
display width color
position height font
float overflow text-overflow
z-index margin text-align
clear padding line-height
list-style 等 outline white-space
border vertical-align
background 等 cursor 等

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.declaration-order {
display: block;
float: right;
position: absolute;
top: 0;
z-index: 9;

border: 1px solid #e5e5e5;
border-radius: 3px;
width: 100px;
height: 100px;

font: normal 13px "HelveticaNeue", sans-serif;
}

1.4.6 其他规范

  • z-index 使用 z-index 属性尽量小,以能实现目标样式为准,页面中的元素内容的z-index不能超过10,不允许直接使用(999~9999)之间的大值
  • color 颜色写小写十六进制,需要用到透明度的除外,如果十六进制的值都一样的简写
  • border 使用border:0 代替 border:none
  • 属性值为0时,不写单位
  • 内外边距 margin padding尽量不要使用百分比,防止屏幕分辨率变化导致样式错乱

(五) Javascript 规范

1.5.1 命名

使用 camelCase (小驼峰式) 命名法

  1. 方法名、参数名、成员变量、局部变量都统一使用 camelCase 风格,禁止采用过于简单的变量命名,例如:let a, b, c
1
正例: localValue / getHttpMessage() / inputUserId 

其中 method 方法命名必须是 动词 或者 动词 +名词 形式

1
2
3
正例:saveShopCarData /openShopCarInfoDialog

反例:save / open / show / go

特此说明,增删查改,详情统一使用如下 5 个单词,不得使用其他(目的是为了统一各个端)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
add / update / delete / detail / get
附:函数方法常用的动词:
get 获取/set 设置
add 增加/remove 删除
create 创建/destory 销毁
start 启动/stop 停止
open 打开/close 关闭
read 读取/write 写入
load 载入/save 保存
begin 开始/end 结束
backup 备份/restore 恢复
import 导入/export 导出
split 分割/merge 合并
inject 注入/extract 提取
attach 附着/detach 脱离
bind 绑定/separate 分离
view 查看/browse 浏览
edit 编辑/modify 修改
select 选取/mark 标记
copy 复制/paste 粘贴
undo 撤销/redo 重做
insert 插入/delete 移除
add 加入/append 添加
clean 清理/clear 清除
index 索引/sort 排序
find 查找/search 搜索
increase 增加/decrease 减少
play 播放/pause 暂停
launch 启动/run 运行
compile 编译/execute 执行
debug 调试/trace 跟踪
observe 观察/listen 监听
build 构建/publish 发布
input 输入/output 输出
encode 编码/decode 解码
encrypt 加密/decrypt 解密
compress 压缩/decompress 解压缩
pack 打包/unpack 解包
parse 解析/emit 生成
connect 连接/disconnect 断开
send 发送/receive 接收
download 下载/upload 上传
refresh 刷新/synchronize 同步
update 更新/revert 复原
lock 锁定/unlock 解锁
check out 签出/check in 签入
submit 提交/commit 交付
push 推/pull 拉
expand 展开/collapse 折叠
enter 进入/exit 退出
abort 放弃/quit 离开
obsolete 废弃/depreciate 废旧
collect 收集/aggregate 聚集
  1. 常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚, 不要嫌名字长
1
2
3
正例: MAX_STOCK_COUNT 

反例: MAX_COUNT

1.5.2 字符串

统一使用单引号(‘‘),不使用双引号(““)。这在创建 HTML 字符串非常有好处:

1
2
3
4
5
6
7
正例:
let str = 'foo';
let testDiv = '<div id="test"></div>';

反例:
let str = 'foo';
let testDiv = "<div id='test'></div>";

1.5.3 对象

  • 使用字面值创建对象
1
2
正例: let user = {};
反例: let user = new Object();
  • 使用字面量来代替对象构造器
1
2
3
4
5
6
7
8
9
10
11
12
正例: 
var user = {
age: 0,
name: 1,
city: 3
};

反例:
var user = new Object();
user.age = 0;
user.name = 0;
user.city = 0;

1.5.4 使用ES6+

必须优先使用 ES6+ 中新增的语法糖和函数。这将简化你的程序,并让你的代码更加灵活和可复用。比如箭头函数、await/async , 解构, let , for…of 等

1.5.5 括号

下列关键字后必须有大括号(即使代码块的内容只有一行):if, else, for, while, do, switch, try, catch, finally, with

1
2
正例: if (condition) { doSomething(); } 
反例: if (condition) doSomething();

1.5.6 undefined 判断

永远不要直接使用 undefined 进行变量判断;使用 typeof 和字符串’undefined’对变量进行判断

1
2
正例: if (typeof person === 'undefined') { ... } 
反例: if (person === undefined) { ... }

1.5.7 其他规则

  • 条件判断和循环最多三层
  • this 转换命名 对上下文 this 的引用使用 self 或者 that 来命名
  • 慎用 console.log

二.注释规范

(一) 插件

2.1.1 下载

vscode 插件市场 下载安装插件koroFileHeader

2.1.2 使用

  1. 文件头部添加注释:
  • 在文件开头添加注释,记录文件信息/文件的传参/出参等。
  • 支持用户高度自定义注释选项, 适配各种需求和注释。
  • 保存文件的时候,自动更新最后的编辑时间和编辑人。
  • 快捷键:window:ctrl+alt+i,mac:ctrl+cmd+i, linux: ctrl+meta+i。
  1. 在光标处添加函数注释:
  • 在光标处自动生成一个注释模板, 自动解析函数参数,生成函数参数注释。
  • 支持用户高度自定义注释选项。
  • 快捷键:window:ctrl+alt+t,mac:ctrl+cmd+t,linux: ctrl+meta+t。
  • 快捷键不可用很可能是被占用了,参考这里

(二) 目录结构规范

2.2.1 文件申明

顶部添加文件申明信息,包括文件描述、原始作者,如果有更新,则需要添加更新内容、更新作者和更新时间

1
2
3
4
5
6
7
8
<!--
* @Author: your name
* @Date: 2021-04-16 15:36:56
* @LastEditTime: 2021-04-19 14:01:02
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \workd:\BMsoft\bmsk\bmguide\frontendguide\comment-standard.md
-->

2.2.2 函数或方法注释

1
2
3
4
5
6
7
8
9
10
/**
* 这是一个求和函数
* @param {Number} a 第一个数字
* @param {Number} b 第二个数字
* @return {Number} 返回两个数字之和
*/

var sum = function(a, b) {
return a + b;
}

2.2.3 模块注释

必须为大区块添加注释,小区块适量注释 模块注释必须单独写在一行

1
2
3
4
5
6
7
8
9
10
/**
* 这是一个求和函数
* @param {Number} a 第一个数字
* @param {Number} b 第二个数字
* @return {Number} 返回两个数字之和
*/

var sum = function(a, b) {
return a + b;
}

三.git 规范

(一) 版本管理

3.1.1 版本规范

项目版本管理要遵循以下规范:

  • 如果是新功能开发,从develop分支创建一个新的分支来开发新功能。
  • 新功能开发完成之后,如果通过了自测,需要提测,把新功能开发的分支合并到develop分支。合并时,先解决冲突,本地启动一下,没有问题,在jenkins上发布到测试环境。
  • 新功能开发完成之后,如果还没有提测,只是开发自测,如果需要发布到开发环境自测,在jenkins修改配置,发布的分支选择新功能分支,然后构建。自测完成之后,把发布分支改回develop分支。
  • 平时修改bug,先在自己的分支修改,没有问题后合并到develop分支,发布到开发环境自测。
  • 测试通过之后,形成一个稳定版本,把develop分支代码合并到master分支,并创建新分支备份此稳定版本。
  • 现场版本升级,如果现场版本拿的是稳定版本,则无需创建新分支备份,如果拿的不是稳定版本,则需要新创建分支备份。
  • 发布到测试环境,一定要先发邮件提测,才可发布,并告知负责人

3.1.2 分支规范

  • master 分支
    • master 为主分支,也是用于部署生产环境的分支,确保master分支稳定性
    • master 分支一般由develop以及hotfix分支合并,任何时间都不能直接修改代码
    • 代码永远是可用的,稳定的,可直接发布的版本
  • develop 分支
    • develop 为开发主分支,代码永远是最新的
    • 新功能都是从以此分支为基准创建自己的 feature 分支来开发
    • 只做合并操作,不能直接在该分支上开发
  • feature 分支
    • 功能开发分支,以 develop 为基准创建
    • 功能开发完成并测试通过后合并回 develop 分支
  • release 分支
    • 预发布分支,在合并好feature分支的develop分支上创建,主要是用来提测的分支
    • 修改好bug并确定稳定之后合并到develop和master分支
    • 这个分支可以通过在 develop 分支打 release tag 的方式来代替
  • hotfix 分支
    • 紧急bug修复分支,以master分支为基线
    • 修复完成后合并到 master 分支 和 develop 分支

(二) 提交代码

3.2.1 步骤

  1. 把修改代码添加提交 git commit -m 'xxx' 注意:提交信息必须表明 修改类型及内容,有条件包含 影响范围

git commit时必须填写符合规范的msg信息,格式为“提交类型: 本次提交的详细说明”,如git commit -m 'feat: 增加某业务删除功能'。提交类型限制以下几种类型,提交时选择最符合本次提交目的的一个,不符合规范将无法进行提交

  • feat: 增加新功能
  • fix: bug修复
  • docs: 文档修改
  • style: 修改代码格式
  • refactor: 代码优化或重构
  • perf: 优化性能
  • test: 改善测试用例
  • build: 改变构建流程,如新增依赖库、工具
  • chore: 非src和test的修改
  • revert: 回滚代码
  1. 拉取代码(如果不拉取代码就推送,会把别人提交的代码给覆盖掉),如果需要合并更改就先合并
  2. 推送

3.2.2 合并分支

将 a 分支合并至 b 分支

  1. 切换至目标分支 b
  2. 运行 git merge a