# 前端代码规范
规范的目的是为了编写高质量的代码,让你的团队成员每天得心情都是愉悦的,大家在一起是快乐的
现代软件架构的复杂性需要协同开发完成,如何高效地协同呢?无规矩不成方圆,无规范难 以协同,对软件来说,适当的规范和标准绝不是消灭代码内容的创造性、优雅性,而是限制过度个性化,以一种普遍认可的统一方式一起做事,提升协作效率,降低沟通成本。代码的字里行间流淌的是软件系统的血液,质量的提升是尽可能少踩坑,杜绝踩重复的坑,切实提升系统稳定性,码出质量。
# 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>
(2)LANG 页面语言
更多关于 lang 属性的说明在这里 (opens new window);
推荐使用属性值 zh-CN
,微软给出了一份详细的语言列表 (opens new window),其中细分了zh-cn, zh-hk, zh-tw。
<html lang="zh-CN">
(3)CHARSET 字符编码
一般情况下统一使用 “UTF-8” 编码
<meta charset="UTF-8">
由于历史原因,有些业务可能会使用 “GBK” 编码
<meta charset="GBK">
(4)IE 兼容模式
如果你想要了解更多,请点击这里 (opens new window);
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
示例:
<!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>
2
3
4
5
6
7
8
9
10
11
# 2.2 缩进
缩进使用 2 个空格(一个 tab)
<div class="jdc">
<a href="#"></a>
</div>
2
3
嵌套的节点应该缩进,每个块状元素独立一行,内联元素可选
正例:
<div>
<h1></h1>
<p></p>
</div>
<p><span></span><span></span></p>
2
3
4
5
反例:
<div>
<h1></h1><p></p>
</div>
<p>
<span></span>
<span></span>
</p>
2
3
4
5
6
7
段落元素与标题元素只能嵌套内联元素
正例:
<h1><span></span></h1>
<p><span></span><span></span></p>
2
反例:
<h1><div></div></h1>
<p><div></div><div></div></p>
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 -->
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 -->
2
3
4
5
6
7
8
9
10
# 2.4 语义化标签
HTML5 中新增很多语义化标签,所以优先使用语义化标签,避免一个页面都是 div 或者 p 标签
示例:
<header></header>
<footer></footer>
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>
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 {
...
}
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>
2
3
4
5
6
正例:
.g-wrap .g-grap-list .item {}
反例:
.g-wrap .g-grap-list li {}
(2)使用直接子选择器
很多前端开发人员写选择器链的时候不使用 直接子选择器(注:直接子选择器和后代选择器的区别)。有时,这可能会导致疼痛的设计问题并且有时候可能会很耗性能。然而,在任何情况下,这是一个非常不好的做法。如果你不写很通用的,需要匹配到 DOM 末端的选择器, 你应该总是考虑直接子选择器。
正例:
.content > .title {
font-size: 2rem;
}
2
3
反例:
.content .title {
font-size: 2rem;
}
2
3
(3)尽量少用通用选择器 * 和 ID 选择器
正例:
.content {}
反例:
*{}
#content {}
2
(4)选择器的嵌套层级应不大于 3 级
正例:
.g-wrap .g-grap-list .item {}
反例:
.g-wrap .g-grap-list .item .title {}
# 3.3 属性缩写
在可以使用缩写的情况下,尽量使用属性缩写。
正例:
.post {
padding: 0 1em 2em;
}
2
3
反例:
.post {
padding-top: 0;
padding-left: 1em;
padding-right: 1em;
padding-bottom: 2em;
}
2
3
4
5
6
# 3.4 属性书写风格
属性书写一般有两种:一种是紧凑格式 (Compact)
.content { display: block; width: 50px; }
一种是展开格式(Expanded)
.content {
display: block;
width: 50px;
}
2
3
4
统一使用展开格式书写样式
# 3.5 代码大小写
样式选择器,属性名,属性值关键字全部使用小写字母书写,属性字符串允许使用大小写。
正例:
.content {
display: block;
}
2
3
反例:
.CONTENT {
DISPLAY: BLOCK;
}
2
3
# 3.6 代码缩进
统一使用 2 个空格进行代码缩进,使得各编辑器表现一致(各编辑器有相关配置)
.content {
display: block;
}
2
3
# 3.7 省略 0 后面的单位
正例:
.content {
padding-bottom: 0;
margin: 0;
}
2
3
4
反例:
.content {
padding-bottom: 0px;
margin: 0em;
}
2
3
4
# 3.8 分号
每个属性声明末尾都要加分号;
.content {
width: 100%;
height: 100%;
}
2
3
4
# 3.9 尽量不使用 !important 声明
当需要强制指定样式且不允许任何场景覆盖时,通过标签内联和 !important 定义样式。
必须注意的是,仅在设计上确实不允许任何其它场景覆盖样式时,才使用内联的 !important 样式。通常在第三方环境的应用中使用这种方案。
如需使用请注释说明
# 3.10 颜色
颜色16进制用小写字母;
颜色16进制尽量用简写。
正例:
.content {
color: #abcdef;
background-color: #fff;
}
2
3
4
反例:
.content {
color: #ABCDEF;
background-color: #ffffff;
}
2
3
4
# 3.11 注释规范
- 注释以字符 /* 开始,以字符 */ 结束
- 注释不能嵌套
/*Comment Text*/
# 单行注释
注释内容第一个字符和最后一个字符都是一个空格字符,单独占一行,行与行之间相隔一行
正例:
/* Comment Text */
.jdc {}
/* Comment Text */
.jdc {}
2
3
4
5
反例:
/*Comment Text*/
.jdc {
display: block;
}
.jdc {
display: block;/*Comment Text*/
}
2
3
4
5
6
7
# 模块注释
注释内容第一个字符和最后一个字符都是一个空格字符,/* 与 模块信息描述占一行,多个横线分隔符-与 */ 占一行,行与行之间相隔两行
正例:
/* Module A
---------------------------------------------------------------- */
.mod-a {}
/* Module B
---------------------------------------------------------------- */
.mod-b {}
2
3
4
5
6
7
8
反例:
/* Module A ---------------------------------------------------- */
.mod-a {}
/* Module B ---------------------------------------------------- */
.mod-b {}
2
3
4
# 文件信息注释
在样式文件编码声明 @charset
语句下面注明页面名称、作者、创建日期等信息
@charset "UTF-8";
/**
* @desc File Info
* @author Author Name
* @date 2015-10-10
*/
2
3
4
5
6
# 4、SCSS/SASS/LESS 规范
SCSS/SASS/LESS 代码的基本规范和原则与 CSS 编码规范保持一致。
# 4.1 顺序组织
- @import;
- 变量声明;
- 样式声明;
@import "mixins/size.less";
@default-text-color: #333;
.page {
width: 960px;
margin: 0 auto;
}
2
3
4
5
6
# 4.2 避免嵌套层级过多
将嵌套深度限制在 3 级。对于超过 4 级的嵌套,给予重新评估。这可以避免出现过于详实的 CSS 选择器。避免大量的嵌套规则。当可读性受到影响时,将之打断。推荐避免出现多于 20 行的嵌套规则出现。
正例:
.g-wrap {
.g-grap-list {}
}
2
3
反例:
.g-wrap {
.g-grap-list {
.item {
.title {}
}
}
}
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;
}
2
3
4
5
(2)不同逻辑、不同语义、不同业务的代码之间插入一个空行分隔开来以提升可读性
说明:任何情形,没有必要插入多个空行进行隔开。
# 5.3 字符串
统一使用单引号(‘),不使用双引号(“)。这在创建 HTML 字符串非常有好处
正例:
let str = 'foo';
let testDiv = '<div id="test"></div>';
2
反例:
let str = 'foo';
let testDiv = "<div id='test'></div>";
2
# 5.4 对象声明
(1)使用字面值创建对象
正例: let user = {};
反例: let user = new Object();
(2)使用字面量来代替对象构造器
正例:
var user = {
age: 0,
name: 1,
city: 3
};
2
3
4
5
反例:
var user = new Object();
user.age = 0;
user.name = 0;
user.city = 0;
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();
}
2
3
反例:
if (condition) doSomething();
# 5.7 undefined 判断
永远不要直接使用 undefined 进行变量判断;使用 typeof 和字符串’undefined’对变量进行判断。
正例:
if (typeof person === 'undefined') {
...
}
2
3
反例:
if (person === undefined) {
...
}
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);
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
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
2
3
4
5
6
- 对所有引用都使用 const,不要使用 var
- 如果引用是可变动的,使用 let 代替 var
原因:let 是块级作用域的,而不像 var 属于函数级作用域
正例:
let count = 1
if (count < 10) {
count += 1
}
2
3
4
反例:
var count = 1
if (count < 10) {
count += 1
}
2
3
4
(3)类型检测
类型检查有三种方式,分别为 typeof
、instanceof
和 Object.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'
2
3
4
5
6
7
8
9
通过 instanceof 操作符可以对引用类型进行判定。
[] instanceof Array // true
({}) instanceof Object // true
(()=>{}) instanceof Function // true
[] instanceof Object // true
{} instanceof Object // true
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]'
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
2
3
4
5
6
(2)多行注释
最少三行, '*'后跟一个空格
建议在以下情况下使用:
- 难于理解的代码段
- 可能存在错误的代码段
- 浏览器特殊的HACK代码
- 业务逻辑强相关的代码
/*
* one space after '*'
*/
var x = 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) {
...
}
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'
// ...
};
2
3
4
反例:
export default {
name: 'Todo',
// ...
}
export default {
name: 'todo-item',
// ...
}
2
3
4
5
6
7
8
9
(2)组件文件名为 pascal-case 格式
正例:
components/
|- my-component.vue
2
反例:
components/
|- myComponent.vue
|- MyComponent.vue
2
3
(3)基础组件文件名为 base 开头,使用完整单词而不是缩写
正例:
components/
|- base-button.vue
|- base-table.vue
|- base-icon.vue
2
3
4
反例:
components/
|- MyButton.vue
|- VueTable.vue
|- Icon.vue
2
3
4
(4)和父组件紧密耦合的子组件应该以父组件名作为前缀命名
正例:
components/
|- todo-list.vue
|- todo-list-item.vue
|- todo-list-item-button.vue
|- user-profile-options.vue (完整单词)
2
3
4
5
反例:
components/
|- TodoList.vue
|- TodoItem.vue
|- TodoButton.vue
|- UProfOpts.vue (使用了缩写)
2
3
4
5
(5)在单文件组件、字符串模板和 JSX 中没有内容的组件应该是自闭合的
正例:
<my-component/>
反例:
<my-component></my-component>
(6)组件的 data 必须是一个函数
当在组件中使用 data 属性的时候(除了 new Vue 外的任何地方),它的值必须是返回一个对象的函数。 因为如果直接是一个对象的话,子组件之间的属性值会互相影响。
正例:
export default {
data () {
return {
name: 'jack'
}
}
}
2
3
4
5
6
7
反例:
export default {
data: {
name: 'jack'
}
}
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: () => [] // 默认值:引用类型返回一个函数
}
}
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>
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>
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"
/>
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"/>
# 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(' ')
}
}
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>
2
3
4
5
6
7
8
9
# 6.3 指令都使用缩写形式
指令推荐都使用缩写形式,(用 : 表示 v-bind: 、用 @ 表示 v-on:、用 # 表示 v-shot:)
正例:
<input
@input="onInput"
@focus="onFocus"
>
2
3
4
反例:
<input
v-on:input="onInput"
@focus="onFocus"
>
2
3
4
# 6.4 标签顺序保持一致
单文件组件应该总是让标签顺序保持为 <template>
、<script>
和 <style>
且 <style>
要放在最后,因为另外两个标签至少要有一个。
正例:
<template>...</template>
<script>...</script>
<style>...</style>
2
3
反例:
<template>...</template>
<style>...</style>
<script>...</script>
2
3
# 6.5 必须为 v-for 设置键值 key
在组件上总是必须用 key 配合 v-for,以便维护内部组件及其子树的状态。
正例:
<ul>
<li
v-for="todo in todos"
:key="todo.id"
>
{{ todo.text }}
</li>
</ul>
2
3
4
5
6
7
8
反例:
<ul>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ul>
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 } });
2
(2)使用路由懒加载(延迟加载)机制
{
path: '/uploadAttachment',
name: 'uploadAttachment',
meta: {
title: '上传附件' },
component: () => import('@/view/components/uploadAttachment/index.vue')
},
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')
}]
}];
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.htmlsrc
这个是重点,我们的源码以及开发的静态资源等都在里面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
配置 ESLintbabel.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)
}
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
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
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)
腾讯:
Bootstrap:编码规范 (opens new window)
ESLint:
prettier:https://prettier.io/
← webrtc