# 前端代码规范

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

现代软件架构的复杂性需要协同开发完成,如何高效地协同呢?无规矩不成方圆,无规范难 以协同,对软件来说,适当的规范和标准绝不是消灭代码内容的创造性、优雅性,而是限制过度个性化,以一种普遍认可的统一方式一起做事,提升协作效率,降低沟通成本。代码的字里行间流淌的是软件系统的血液,质量的提升是尽可能少踩坑,杜绝踩重复的坑,切实提升系统稳定性,码出质量。

# 1、命名规范

由历史原因及个人习惯引起的 DOM 结构、命名不统一,导致不同成员在维护同一页面时,效率低下,迭代、维护成本极高。

# 1.1 项目命名

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

正例:mall-management-system

反例:mall_management-system / mallManagementSystem

# 1.2 目录命名

全部采用小写方式, 以中划线分隔,有复数结构时,要采用复数命名法, 缩写不用复数。

正例: scripts / styles / images / utils / layouts / demo-styles / demo-scripts / img / doc

反例: script / style / demo_scripts / demoStyles / imgs / docs

【特殊】VUE 的项目中的 所有组件目录,使用 kebab-case 命名。

正例: head-search / page-loading / authorized / notice-icon

反例: HeadSearch / PageLoading

# 1.3 文件命名

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

正例: render-dom.js / signup.css / index.html / company-logo.png

反例: renderDom.js / UserManagement.html

# 1.4 命名严谨性

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

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

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

反例:DaZhePromotion [打折] / getPingfenByName() [评分] / int 某变量 = 3

# 2、HTML 规范

# 2.1 HTML 类型

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

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

(1)DOCTYPE 声明

HTML文件必须加上 DOCTYPE 声明,并统一使用 HTML5 的文档声明

虽然 DOCTYPE 不区分大小写,但是按照惯例,DOCTYPE 大写(关于html属性,大写还是小写) (opens new window)

<!DOCTYPE html>
1

(2)LANG 页面语言

更多关于 lang 属性的说明在这里 (opens new window)

推荐使用属性值 zh-CN ,微软给出了一份详细的语言列表 (opens new window),其中细分了zh-cn, zh-hk, zh-tw。

<html lang="zh-CN">
1

(3)CHARSET 字符编码

一般情况下统一使用 “UTF-8” 编码

<meta charset="UTF-8">
1

由于历史原因,有些业务可能会使用 “GBK” 编码

<meta charset="GBK">
1

有关 charset (opens new window)

(4)IE 兼容模式

如果你想要了解更多,请点击这里 (opens new window)

<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
1

示例:

<!DOCTYPE html>
<html lang="zh-CN">
  <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
2
3
4
5
6
7
8
9
10
11

# 2.2 缩进

缩进使用 2 个空格(一个 tab)

<div class="jdc">
  <a href="#"></a>
</div>
1
2
3

嵌套的节点应该缩进,每个块状元素独立一行,内联元素可选

正例:

<div>
  <h1></h1>
  <p></p>
</div>	
<p><span></span><span></span></p>
1
2
3
4
5

反例:

<div>
  <h1></h1><p></p>
</div>	
<p> 
  <span></span>
  <span></span>
</p>
1
2
3
4
5
6
7

段落元素与标题元素只能嵌套内联元素

正例:

<h1><span></span></h1>
<p><span></span><span></span></p>
1
2

反例:

<h1><div></div></h1>
<p><div></div><div></div></p>
1
2

# 2.3 分块注释

在每一个块状元素,元素前和元素后,加上一对 HTML 注释。

注释内容前后各一个空格字符,<!-- S Comment Text --> 表示模块开始,<!-- E Comment Text --> 表示模块结束,模块与模块之间相隔一行

正例:

<!-- S Comment Text A -->
<div>
  ...
</div>
<!-- E Comment Text A -->

<!-- S Comment Text B -->
<div>
  ...
</div>
<!-- E Comment Text B -->
1
2
3
4
5
6
7
8
9
10
11

反例:

<!-- S Comment Text A -->
<div>
  ...
</div>
<!-- E Comment Text A -->
<!-- S Comment Text B -->
<div>
  ...
</div>
<!-- E Comment Text B -->
1
2
3
4
5
6
7
8
9
10

# 2.4 语义化标签

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

示例:

<header></header>
<footer></footer>
1
2

# 2.5 属性

(1)属性名必须使用小写字母。

正例:<table cellspacing="0">...</table>

反例:<table cellSpacing="0">...</table>

(2)属性值使用双引号(" ") 而不是单引号('')

正例:<div class="box"></div>

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

(3)布尔类型的属性,建议不添加属性值。

示例:

<input type="text" disabled>
<input type="checkbox" value="1" checked>
1
2

(4)自定义属性建议以 xxx- 为前缀,推荐使用 data-。

使用前缀有助于区分自定义属性和标准定义的属性。

示例:<ol data-ui-type="select"></ol>

# 2.6 引入 CSS, JS

(1)根据 HTML5 规范, 通常在引入 CSS 和 JS 时不需要指明 type,因为 text/css 和 text/javascript 分别是他们的默认值。

(2)在 head 中引入页面需要的所有 CSS 资源。

(3)JavaScript 应当放在页面末尾,或采用异步加载。

(4)移动环境或只针对现代浏览器设计的 Web 应用,如果引用外部资源的 URL 协议部分与页面相同,建议省略协议前缀。

<script src="//s1.bdstatic.com/cache/static/jquery-1.10.2.min_f2fb5194.js"></script>

# 3、CSS 规范

# 3.1 命名

  • 类名使用小写字母,以中划线分隔
  • id 采用驼峰式命名
  • scss 中的变量、函数、混合、placeholder 采用驼峰式命名

示例:

/* class */
.element-content {
    ...
}

/* id */
#myDialog {
    ...
}

/* 变量 */
$colorBlack: #000;

/* 函数 */
@function pxToRem($px) {
    ...
}

/* 混合 */
@mixin centerBlock {
    ...
}

/* placeholder */
%myDialog {
    ...
}
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

# 3.2 选择器

(1)css 选择器中避免使用标签名

从结构、表现、行为分离的原则来看,应该尽量避免 css 中出现 HTML 标签,并且在 css 选择器中出现标签名会存在潜在的问题。

例子:

<div class="g-wrap">
  <ul class="g-wrap-list">
    <li class="item"></li>
    <li class="item"></li>
  </ul>
</div>
1
2
3
4
5
6

正例:

.g-wrap .g-grap-list .item {}
1

反例:

.g-wrap .g-grap-list li {}
1

(2)使用直接子选择器

很多前端开发人员写选择器链的时候不使用 直接子选择器(注:直接子选择器和后代选择器的区别)。有时,这可能会导致疼痛的设计问题并且有时候可能会很耗性能。然而,在任何情况下,这是一个非常不好的做法。如果你不写很通用的,需要匹配到 DOM 末端的选择器, 你应该总是考虑直接子选择器。

正例:

.content > .title {
  font-size: 2rem;
}
1
2
3

反例:

.content .title {
  font-size: 2rem;
}
1
2
3

(3)尽量少用通用选择器 * 和 ID 选择器

正例:

.content {}
1

反例:

*{}
#content {}
1
2

(4)选择器的嵌套层级应不大于 3 级

正例:

.g-wrap .g-grap-list .item {}
1

反例:

.g-wrap .g-grap-list .item .title {}
1

# 3.3 属性缩写

在可以使用缩写的情况下,尽量使用属性缩写。

正例:

.post {
  padding: 0 1em 2em;
}
1
2
3

反例:

.post {
  padding-top: 0;
  padding-left: 1em;
  padding-right: 1em;
  padding-bottom: 2em;
}
1
2
3
4
5
6

# 3.4 属性书写风格

属性书写一般有两种:一种是紧凑格式 (Compact)

.content { display: block; width: 50px; }
1

一种是展开格式(Expanded)

.content {
  display: block;
  width: 50px;
}
1
2
3
4

统一使用展开格式书写样式

# 3.5 代码大小写

样式选择器,属性名,属性值关键字全部使用小写字母书写,属性字符串允许使用大小写。

正例:

.content {
  display: block;
}
1
2
3

反例:

.CONTENT {
  DISPLAY: BLOCK;
}
1
2
3

# 3.6 代码缩进

统一使用 2 个空格进行代码缩进,使得各编辑器表现一致(各编辑器有相关配置)

.content {
  display: block;
}
1
2
3

# 3.7 省略 0 后面的单位

正例:

.content {
  padding-bottom: 0;
  margin: 0;
}
1
2
3
4

反例:

.content {
  padding-bottom: 0px;
  margin: 0em;
}
1
2
3
4

# 3.8 分号

每个属性声明末尾都要加分号;

.content {
  width: 100%;
  height: 100%;
}
1
2
3
4

# 3.9 尽量不使用 !important 声明

当需要强制指定样式且不允许任何场景覆盖时,通过标签内联和 !important 定义样式。

必须注意的是,仅在设计上确实不允许任何其它场景覆盖样式时,才使用内联的 !important 样式。通常在第三方环境的应用中使用这种方案。

如需使用请注释说明

# 3.10 颜色

颜色16进制用小写字母;

颜色16进制尽量用简写。

正例:

.content {
  color: #abcdef;
  background-color: #fff;
}
1
2
3
4

反例:

.content {
  color: #ABCDEF;
  background-color: #ffffff;
}
1
2
3
4

# 3.11 注释规范

  • 注释以字符 /* 开始,以字符 */ 结束
  • 注释不能嵌套
/*Comment Text*/
1

# 单行注释

注释内容第一个字符和最后一个字符都是一个空格字符,单独占一行,行与行之间相隔一行

正例:

/* Comment Text */
.jdc {}

/* Comment Text */
.jdc {}
1
2
3
4
5

反例:

/*Comment Text*/
.jdc {
	display: block;
}
.jdc {
	display: block;/*Comment Text*/
}
1
2
3
4
5
6
7

# 模块注释

注释内容第一个字符和最后一个字符都是一个空格字符,/* 与 模块信息描述占一行,多个横线分隔符-与 */ 占一行,行与行之间相隔两行

正例:

/* Module A
---------------------------------------------------------------- */
.mod-a {}


/* Module B
---------------------------------------------------------------- */
.mod-b {}
1
2
3
4
5
6
7
8

反例:

/* Module A ---------------------------------------------------- */
.mod-a {}
/* Module B ---------------------------------------------------- */
.mod-b {}
1
2
3
4

# 文件信息注释

在样式文件编码声明 @charset 语句下面注明页面名称、作者、创建日期等信息

@charset "UTF-8";
/**
 * @desc File Info
 * @author Author Name
 * @date 2015-10-10
 */
1
2
3
4
5
6

# 4、SCSS/SASS/LESS 规范

SCSS/SASS/LESS 代码的基本规范和原则与 CSS 编码规范保持一致。

# 4.1 顺序组织

  1. @import;
  2. 变量声明;
  3. 样式声明;
@import "mixins/size.less";
@default-text-color: #333;
.page {
width: 960px;
margin: 0 auto;
}
1
2
3
4
5
6

# 4.2 避免嵌套层级过多

将嵌套深度限制在 3 级。对于超过 4 级的嵌套,给予重新评估。这可以避免出现过于详实的 CSS 选择器。避免大量的嵌套规则。当可读性受到影响时,将之打断。推荐避免出现多于 20 行的嵌套规则出现。

正例:

.g-wrap {
  .g-grap-list {}
}
1
2
3

反例:

.g-wrap {
  .g-grap-list {
    .item {
      .title {}
    }
  }
}
1
2
3
4
5
6
7

# 4.3 其他

不允许有空的规则;

不要在同个规则里出现重复的属性,如果重复的属性是连续的则没关系;

不要在一个文件里出现两个相同的规则;

# 5、JavaScript 规范

# 5.1 命名

(1)采用小写驼峰命名 lowerCamelCase,代码中的命名均不能以下划线,也不能以下划线或美元符号结束

反例: _name / name_ / name$

(2)方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从驼峰形式

正例: localValue / getHttpMessage() / inputUserId

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

正例:saveShopCarData /openShopCarInfoDialog

反例:save / open / show / go

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

add / delete / get / update / detail

附: 函数方法常用的动词:

  • 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 聚集;

(3)常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长

正例: MAX_STOCK_COUNT

反例: MAX_COUNT

# 5.2 代码格式

(1)使用 2 个空格进行缩进

if (x < y) {
  x += 10;
} else {
  x += 1;
}
1
2
3
4
5

(2)不同逻辑、不同语义、不同业务的代码之间插入一个空行分隔开来以提升可读性

说明:任何情形,没有必要插入多个空行进行隔开。

# 5.3 字符串

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

正例:

let str = 'foo';
let testDiv = '<div id="test"></div>';
1
2

反例:

let str = 'foo';
let testDiv = "<div id='test'></div>";
1
2

# 5.4 对象声明

(1)使用字面值创建对象

正例: let user = {};

反例: let user = new Object();

(2)使用字面量来代替对象构造器

正例:

var user = {
  age: 0,
  name: 1,
  city: 3
};
1
2
3
4
5

反例:

var user = new Object();
user.age = 0;
user.name = 0;
user.city = 0;
1
2
3
4

# 5.5 使用 ES6+

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

# 5.6 括号

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

正例:

if (condition) {
  doSomething();
}
1
2
3

反例:

if (condition) doSomething();
1

# 5.7 undefined 判断

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

正例:

if (typeof person === 'undefined') {
  ... 
}
1
2
3

反例:

if (person === undefined) {
  ... 
}
1
2
3

# 5.8 条件判断和循环最多三层

条件判断能使用三目运算符和逻辑运算符解决的,就不要使用条件判断,但是谨记不要写太长的三目运算符。如果超过 3 层请抽成函数,并写清楚注释。

# 5.9 this 的转换命名

对上下文 this 的引用只能使用 ’self’ 来命名

# 5.10 慎用 console.log

因 console.log 大量使用会有性能问题,所以在非 webpack 项目中谨慎使用 log 功能。

# 5.11 分号

以下几种情况后需加分号:

  • 变量声明
  • 表达式
  • return
  • throw
  • break
  • continue
  • do-while
/* var declaration */
var x = 1;

/* expression statement */
x++;

/* do-while */
do {
  x++;
} while (x < 10);
1
2
3
4
5
6
7
8
9
10

# 5.12 类型

(1)原始类型:存取原始类型直接作用于值本身

  • String(字符串)
  • Number(数字)
  • Boolean(布尔)
  • BigInt(任意大整数)
  • Null(空值)
  • Undefined(未定义)
  • Symbol(符号)
const foo = 1
let bar = foo

bar = 9

console.log(foo, bar) // 1, 9
1
2
3
4
5
6

(2)引用类型:访问复杂类型作用于值的引用

  • Object
  • Array
  • Function
  • Date
  • RegExp
  • Math
  • Map
const foo = [1, 2, 3]
const bar = foo

bar[0] = 9

console.log(foo[0], bar[0]) // 9, 9
1
2
3
4
5
6
  • 对所有引用都使用 const,不要使用 var
  • 如果引用是可变动的,使用 let 代替 var

原因:let 是块级作用域的,而不像 var 属于函数级作用域

正例:

let count = 1
if (count < 10) {
  count += 1
}
1
2
3
4

反例:

var count = 1
if (count < 10) {
  count += 1
}
1
2
3
4

(3)类型检测

类型检查有三种方式,分别为 typeofinstanceofObject.prototype.toString()

通过 typeof 操作符来判断一个值属于哪种原始类型。

typeof 'seymoe' // 'string'
typeof true // 'boolean'
typeof 10 // 'number'
typeof Symbol() // 'symbol'
typeof null // 'object' 无法判定是否为 null
typeof undefined // 'undefined'
typeof {} // 'object'
typeof [] // 'object'
typeof(() => {}) // 'function'
1
2
3
4
5
6
7
8
9

通过 instanceof 操作符可以对引用类型进行判定。

[] instanceof Array // true
({}) instanceof Object // true
(()=>{}) instanceof Function // true

[] instanceof Object // true
{} instanceof Object // true
1
2
3
4
5
6

通过 Object.prototype.toString() 可以判定 JavaScript 中所有数据类型

Object.prototype.toString.call({}) // '[object Object]'
Object.prototype.toString.call([]) // '[object Array]'
Object.prototype.toString.call(() => {}) // '[object Function]'
Object.prototype.toString.call('seymoe') // '[object String]'
Object.prototype.toString.call(1) // '[object Number]'
Object.prototype.toString.call(true) // '[object Boolean]'
Object.prototype.toString.call(Symbol()) // '[object Symbol]'
Object.prototype.toString.call(null) // '[object Null]'
Object.prototype.toString.call(undefined) // '[object Undefined]'

Object.prototype.toString.call(new Date()) // '[object Date]'
Object.prototype.toString.call(Math) // '[object Math]'
Object.prototype.toString.call(new Set()) // '[object Set]'
Object.prototype.toString.call(new WeakSet()) // '[object WeakSet]'
Object.prototype.toString.call(new Map()) // '[object Map]'
Object.prototype.toString.call(new WeakMap()) // '[object WeakMap]'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 5.13 注释

(1)单行注释

必须独占一行。// 后跟一个空格,缩进与下一行被注释说明的代码一致。可位于一个代码行的末尾,与代码间隔一个空格。

if (condition) {
    // if you made it here, then all security checks passed
    allowed();
}

let zhangsan = 'zhangsan'; // one space after code
1
2
3
4
5
6

(2)多行注释

最少三行, '*'后跟一个空格

建议在以下情况下使用:

  • 难于理解的代码段
  • 可能存在错误的代码段
  • 浏览器特殊的HACK代码
  • 业务逻辑强相关的代码
/*
 * one space after '*'
 */
var x = 1;
1
2
3
4

(3)文档注释

各类标签 @param , @method 等请参考 usejsdoc (opens new window)JSDoc Guide (opens new window)

建议在以下情况下使用:

  • 所有常量
  • 所有函数
  • 所有类
/**
 * @func
 * @desc 一个带参数的函数
 * @param {string} a - 参数a
 * @param {number} b=1 - 参数b默认值为1
 * @param {string} c=1 - 参数c有两种支持的取值</br>1—表示x</br>2—表示xx
 * @param {object} d - 参数d为一个对象
 * @param {string} d.e - 参数d的e属性
 * @param {string} d.f - 参数d的f属性
 * @param {object[]} g - 参数g为一个对象数组
 * @param {string} g.h - 参数g数组中一项的h属性
 * @param {string} g.i - 参数g数组中一项的i属性
 * @param {string} [j] - 参数j是一个可选参数
 */
function foo(a, b, c, d, g, j) {
    ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 5.14 其他

  • 用'===', '!=='代替'==', '!=';
  • 不要在内置对象的原型上添加方法,如Array, Date;
  • debugger 不要出现在提交的代码里;
  • 不允许有空的代码块。
  • 避免使用 eval 和 with

# 6、Vue 项目规范

vue 项目规范以 Vue 官方规范 (https://cn.vuejs.org/v2/style-guide/) 中的 A 规范为基础,在其上面进行项目开发,故所有代码均遵守该规范。请仔仔细细阅读 Vue 官方规范,切记,此为第一步。

# 6.1 组件规范

(1)组件名为多个单词

组件名应该始终是多个单词组成(大于等于 2),且命名规范为 kebab-case 格式。

这样做可以避免跟现有的以及未来的 HTML 元素相冲突,因为所有的 HTML 元素名称都是单个单词的。

正例:

export default {
  name: 'TodoItem' 
  // ... 
};
1
2
3
4

反例:

export default {
  name: 'Todo',
  // ... 
}

export default {
  name: 'todo-item', 
  // ...
}
1
2
3
4
5
6
7
8
9

(2)组件文件名为 pascal-case 格式

正例:

components/
|- my-component.vue
1
2

反例:

components/
|- myComponent.vue
|- MyComponent.vue
1
2
3

(3)基础组件文件名为 base 开头,使用完整单词而不是缩写

正例:

components/
|- base-button.vue
|- base-table.vue
|- base-icon.vue
1
2
3
4

反例:

components/
|- MyButton.vue
|- VueTable.vue
|- Icon.vue
1
2
3
4

(4)和父组件紧密耦合的子组件应该以父组件名作为前缀命名

正例:

components/
|- todo-list.vue
|- todo-list-item.vue
|- todo-list-item-button.vue
|- user-profile-options.vue (完整单词)
1
2
3
4
5

反例:

components/
|- TodoList.vue
|- TodoItem.vue
|- TodoButton.vue
|- UProfOpts.vue (使用了缩写)
1
2
3
4
5

(5)在单文件组件、字符串模板和 JSX 中没有内容的组件应该是自闭合的

正例:

<my-component/>
1

反例:

<my-component></my-component>
1

(6)组件的 data 必须是一个函数

当在组件中使用 data 属性的时候(除了 new Vue 外的任何地方),它的值必须是返回一个对象的函数。 因为如果直接是一个对象的话,子组件之间的属性值会互相影响。

正例:

export default {
  data () {
    return {
      name: 'jack'
    }
  }
}
1
2
3
4
5
6
7

反例:

export default {
  data: {
    name: 'jack'
  }
}
1
2
3
4
5

(7)Prop 定义应该尽量详细

  • 必须使用 camelCase 驼峰命名
  • 必须指定类型
  • 必须加上注释,表明其含义
  • 必须加上 required 或者 default,两者二选其一
  • default 原始类型直接返回,引用类型返回一个函数
  • 如果有业务需要,必须加上 validator 验证
props: {
  // 组件状态,用于控制组件的颜色
  status: {
    type: String, 
    required: true, // 是否必填
    validator: function (value) {
      return [
        'succ',
        'info',
        'error'
      ].indexOf(value) !== -1
    }
  },
  // 用户级别,用于显示皇冠个数
  userLevel:{
    type: String,
    default: '' // 默认值:原始类型直接返回
  },
  // 搜索列表
  searchList: {
    type: Array,
    default: () => [] // 默认值:引用类型返回一个函数
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

(8)为组件样式设置作用域

正例:

<template>
  <button class="btn btn-close">X</button>
</template>

<!-- 使用 `scoped` 特性 -->
<style scoped>
.btn-close {
  background-color: red;
}
</style>
1
2
3
4
5
6
7
8
9
10

反例:

<template>
  <button class="btn btn-close">X</button>
</template>

<!-- 没有使用 `scoped` 特性 -->
<style>
.btn-close {
  background-color: red;
}
</style>
1
2
3
4
5
6
7
8
9
10

(9)如果特性元素较多,应该主动换行

正例:

<my-component foo="a" bar="b" baz="c"
foo="a" bar="b" baz="c"
foo="a" bar="b" baz="c"
/>
1
2
3
4

反例:

<my-component foo="a" bar="b" baz="c" foo="a" bar="b" baz="c" foo="a" bar="b" baz="c" foo="a" bar="b" baz="c"/>
1

# 6.2 模板中使用简单的表达式

组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。复杂表达式会让你的模板变得不那么声明式。我们应该尽量描述应该出现的是什么,而非如何计算那个值。而且计算属性和方法使得代码可以重用。

正例:

<template>
  <p>{{ normalizedFullName }}</p>
</template>

// 复杂表达式已经移入一个计算属性
computed: {
  normalizedFullName: function () {
    return this.fullName.split(' ').map(function (word) {
      return word[0].toUpperCase() + word.slice(1)
    }).join(' ')
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

反例:

<template>
  <p>
    {{
      fullName.split(' ').map(function (word) {
        return word[0].toUpperCase() + word.slice(1)
      }).join(' ')
    }}
  </p>
</template>
1
2
3
4
5
6
7
8
9

# 6.3 指令都使用缩写形式

指令推荐都使用缩写形式,(用 : 表示 v-bind: 、用 @ 表示 v-on:、用 # 表示 v-shot:)

正例:

<input
  @input="onInput" 
  @focus="onFocus" 
>
1
2
3
4

反例:

<input
  v-on:input="onInput" 
  @focus="onFocus" 
>
1
2
3
4

# 6.4 标签顺序保持一致

单文件组件应该总是让标签顺序保持为 <template><script><style>

<style> 要放在最后,因为另外两个标签至少要有一个。

正例:

<template>...</template>
<script>...</script>
<style>...</style>
1
2
3

反例:

<template>...</template>
<style>...</style>
<script>...</script>
1
2
3

# 6.5 必须为 v-for 设置键值 key

在组件上总是必须用 key 配合 v-for,以便维护内部组件及其子树的状态。

正例:

<ul>
  <li
    v-for="todo in todos"
    :key="todo.id"
  >
    {{ todo.text }}
  </li>
</ul>
1
2
3
4
5
6
7
8

反例:

<ul>
  <li v-for="todo in todos">
    {{ todo.text }}
  </li>
</ul>
1
2
3
4
5

# 6.6 v-show 与 v-if 选择

如果运行时,需要非常频繁地切换,使用 v-show ;如果在运行时,条件很少改变,使用 v-if。

# 6.7 script 标签内部结构顺序

name > components > mixins > props > data > computed > watch > filter > 生命周期钩子函数(钩子函数按其 执行顺序) > method

生命周期钩子执行顺序:

  • beforeCreate
  • created
  • beforeMount
  • mounted
  • beforeUpdate
  • updated
  • activated
  • deactivated
  • beforeDestroy
  • destroyed

# 6.8 Vue Router 规范

(1)页面跳转数据传递使用路由参数

页面跳转,例如 A 页面跳转到 B 页面,需要将 A 页面的数据传递到 B 页面,推荐使用 路由参数进行传参,而不是将需要传递的数据保存 vuex,然后在 B 页面取出 vuex 的数据,因为如果在 B 页面刷新会导致 vuex 数据丢失,导致 B 页面无法正常显示数据。

let id = ' 123';
this.$router.push({ name: 'userCenter', query: { id: id } });
1
2

(2)使用路由懒加载(延迟加载)机制

{
  path: '/uploadAttachment', 
  name: 'uploadAttachment', 
  meta: {
  title: '上传附件' },
  component: () => import('@/view/components/uploadAttachment/index.vue')
},
1
2
3
4
5
6
7

(3)router 中的命名规范

path、childrenPoints 命名规范采用 kebab-case 命名规范(尽量 vue 文件的目录结构保持一致,因为目录、文件名都是 kebab-case,这样很方便找到对应的文件)name 命名规范采用 kebab-case 命名规范且和 component 组件名保持一致!(因为要保持 keep-alive 特性,keep-alive 按照 component 的 name 进行缓存,所以两者必须高度保持一致)

// 动态加载
export const reload = [{
  path: '/reload', 
  name: 'reload', 
  component: Main, 
  meta: {
  title: '动态加载',
  icon: 'icon iconfont' },
  children: [{
    path: '/reload/smart-reload-list', 
    name: 'SmartReloadList', 
    meta: {
      title: 'SmartReload', 
      childrenPoints: [
        { title: '查询', name: 'smart-reload-search' },
        { title: '执行 reload', name: 'smart-reload-update' },
        { title: '查看执行结果', name: 'smart-reload-result' }
      ]
    },
    component: () => import('@/views/reload/smart-reload/smart-reload-list.vue')
  }]
}];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 6.9 Vue 目录规范

vue 项目中的所有命名一定要与后端命名统一。

比如权限:后端 privilege, 前端无论 router , store, api 等都必须使用 privielege 单词!

(1)使用 Vue-cli 脚手架

使用 vue-cli4 来初始化项目,项目名按照上面的命名规范。

(2)目录说明

  • node_modules 第三方依赖,我们安装的各种依赖都在个文件件里面
  • public 存放公共资源的地方,里面有一个index.html
  • src 这个是重点,我们的源码以及开发的静态资源等都在里面
    • api 所有 api 接口
    • assets 静态资源,css、img、js、font 等
    • compoments 自定义的公共组件
    • config 配置信息
    • constants 常量信息,项目所有 Enum, 全局常量等
    • directives 自定义指令
    • lib 外部引用的插件存放及修改文件
    • mock 模拟接口,临时存放
    • plugins 插件,全局使用
    • router 路由配置,用于页面的跳转配置
    • store 是 vuex 的文件,主要用于项目里边的一些状态保存。比如 state、mutations、actions、getters、modules。
    • views 视图组件
      • user-page user 页面目录
        • compoments 页面组件
        • fields.js 页面纯数据
        • view.vue 页面视图
  • App.vue 首页组件(默认组件),也叫根组件
  • main.js 程序入口文件
  • .browserslistrc 配置使用CSS兼容性插件的使用范围
  • .eslintrc.js 配置 ESLint
  • babel.config.js 配置 babel 预设
  • package.json 项目描述及依赖
  • package-lock.json 版本管理使用的文件
  • vue.config.js 可选的配置文件,用于项目全局配置相关

(3)api 目录

  • 文件、变量命名要与后端保持一致。
  • 此目录对应后端 API 接口,按照后端一个 controller 一个 api.js 文件。若项目较大时,可 以按照业务划分子目录,并与后端保持一致。
  • api 中的方法名字要与后端 api url 尽量保持语义高度一致性。
  • 对于 api 中的每个方法要添加注释,注释与后端 swagger 文档保持一致
后端 url: EmployeeController.java
/employee/add
/employee/delete/{id}
/employee/update

前端: employee.js
// 添加员工
function addEmployee(data) {
return postAxios('/employee/add', data)
}
// 更新员工信息
function updateEmployee(data) {
return postAxios('/employee/update', data)
}
// 删除员工
function deleteEmployee(employeeId) {
return postAxios('/employee/delete/' + employeeId)
}
// 获取员工信息
function getEmployee(data) {
return postAxios('/employee/get/', data)
}
// 获取员工信息列表
function getEmployeeList(data) {
return postAxios('/employee/getlist/', data)
}

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

(4)assets 目录

assets 为静态资源,里面存放 images, styles, icons 等静态资源,静态资源命名格式为 kebab-case

|assets
|-- icons
|-- images
| |-- background-color.png
| |-- upload-header.png
|-- style
1
2
3
4
5
6

(5)components 目录

此目录应按照组件进行目录划分,目录命名为 kebab-case,组件命名规则也为 kebab-case

|components
|-- error-log
| |-- index.vue
| |-- index.less
|-- markdown-editor
| |-- index.vue
| |-- index.js
|-- kebab-case
1
2
3
4
5
6
7
8

(6)router 与 store 目录

这两个目录一定要将业务进行拆分,不能放到一个 js 文件里。

router 尽量按照 views 中的结构保持一致

store 按照业务进行拆分不同的 js 文件

# 6.10 注释说明

整理必须加注释的地方

  • 公共组件使用说明
  • api 目录的接口 js 文件必须加注释
  • store 中的 state, mutation, action 等必须加注释
  • vue 文件中的 template 必须加注释,若文件较大添加 start end 注释
  • vue 文件的 methods,每个 method 必须添加注释
  • vue 文件的 data, 非常见单词要加注释

# 6.11 其他

(1)尽量不要手动操作 DOM

因使用 vue 框架,所以在项目开发中尽量使用 vue 的数据驱动更新 DOM,尽量(不到万不得已)不要手动操作 DOM,包括:增删改 dom 元素、以及更改样式、添加事件等。

(2)删除无用代码

因使用了 git/svn 等代码版本工具,对于无用代码必须及时删除,例如:一些调试的 console 语句、无用的弃用功能代码

# 7、参考

阿里:Airbnb JavaScript 风格指南 (opens new window)

腾讯:

京东:凹凸实验室 (opens new window)

百度:前端规范 (opens new window)

网易:规范 (opens new window)

Vue:风格指南 (opens new window)

ES6:编程风格 (opens new window)

Bootstrap:编码规范 (opens new window)

ESLint:

prettier:https://prettier.io/

上次更新: 12/26/2021, 10:35:55 PM