1 概述※
1.1 编写目的※
本规范旨在建立统一的编程和项目管理标准,提升软件项目的可维护性、可扩展性、团队协作效率以及前端代码质量。具体而言,其主要编写目的包括但不限于以下几个方面:
确保代码一致性:通过制定统一的编程风格和命名规则,保证不同前端开发者编写的代码在风格上保持一致,便于团队成员之间相互理解和维护。
提高代码质量:规范中包含的编码最佳实践、性能优化建议和异常处理指导等,有助于减少错误和漏洞,提升软件的稳定性和可靠性。
促进高效协作:明确的项目结构、版本控制流程和代码审查标准,有助于简化团队协作流程。
简化维护工作:良好的文档注释规范和模块化设计原则使得后续的代码维护和升级工作更加容易进行,降低长期维护成本。
增强可读性和可理解性:遵循规范编写的代码逻辑清晰、易于阅读,新加入的团队成员能更快地熟悉项目,降低学习曲线。
保障安全合规:安全性规范的制定和执行能有效预防常见的安全威胁,如注入攻击、跨站脚本等,保护用户数据和系统安全。
综上所述,前端开发规范对构建高质量软件产品至关重要,开发人员不仅需要关注技术细节,还需要着眼于团队合作、项目管理和长期发展,是前端开发人员重要的指导文件。
1.2 适用范围※
本规范基于Vue 2.6+版本前端项目。
1.3 研发要求※
优先使用集团统一研发基础支撑平台及共性技术组件进行开发,使用平台代码生成工具构建基础代码。
1.4 内容说明※
本规范以前端开发者为中心视角,划分为:命名规范、HTML编程实践及规范、CSS编程实践及规范、JavaScript编程实践及规范、Vue2项目规范、React项目规范六个部分,再根据内容特征,细分成若干二级、三级子目录。另外,依据实用程度和优先级,依次分为【高】、【中】、【低】三大类。在延伸信息中,“说明”对规约做了适当扩展和解释;“正例”提倡什么样的编码和实现方式;“反例”说明需要提防的雷区,以及真实的错误案例。
1.5 参考规范※
阿里前端开发手册
Google JavaScript 编程风格指南
2 命名规范※
2.1 通用规范※
【高】编码过程中所有命名均不能以下划线或美元符号、特殊字符等开始,也不能以下划线或美元符号、特殊字符结束。
反例:
_name、__name、$name、name_、name$、name__
【高】所有编码相关的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。
说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,纯拼音命名方式更要避免采用。
正例:
sgit、sgcc、taobao、cainiao、aliyun、youku、Beijing 等国际通用的名称,可视同英文
反例:
DaZhePromotion [打折]、getPingfenByName() [评分]、String fw[福娃]、int 某变量 = 3
【中】杜绝完全不规范的缩写。
反例:
Condition 缩写成 condi;
Function 缩写成 Fu,此类随意缩写严重降低了代码的可阅读性。
【中】为了达到代码自解释的目标,任何自定义编程元素在命名时,使用尽量完整的单词组合来表达。
2.2 项目命名※
【高】全部采用小写方式,以下划线分隔。
正例:
my_project_name
2.3 文件编码※
【高】源文件编码格式为UTF-8。
2.4 目录命名※
【高】目录命名全部采用小写方式,以中划线分隔,有复数结构时,要采用复数命名法,缩写不用复数。
正例:
scripts / styles / components / images / utils / layouts / demo-styles / img / doc
反例:
script / style / demo_scripts / demoStyles / imgs / docs
(说明:kebab-case是一种命名约定驼峰命名。其特点包括:单词之间使用连字符(-)分隔,而不是下划线或空格;所有字母都小写,不使用任何大写字母。)
2.5 命名严谨性规范※
【高】代码中的命名严禁使用汉语拼音与英文混合的方式,更不允许直接使用中文的方式。
说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,即使纯拼音命名方式也要避免采用。
正例:
henan / luoyang / usrInfo等国际通用的名称,可视同英文
反例:
YongDianLiang[用电量]
getPingfenByName() [评分]
int 某变量 = 3
【高】杜绝完全不规范的缩写,此类随意缩写严重降低了代码的可阅读性,严重影响了代码的可读性:
反例:
condition “缩写”命名成 cond
3 HTML编程实践及规范※
3.1 优先选择HTML5※
【高】使用text/html 格式的 HTML,避免使用 XHTML。XHTML 以及它的属性如 application/xhtml+xml 在浏览器中的应用支持与优化空间都十分有限。推荐使用 HTML5 的文档类型申明。
【高】全部采用小写方式以中划线分隔的方式命名HTML文件,避免使用特殊字符和汉字,不能包含空格。
正例:
index.html
about-us.html
contact-form.html
products-list.html
3.2 HTML代码格式规范※
【高】缩进使用soft tab(4个空格);
【高】嵌套的节点应该缩进;
【高】在属性上,使用双引号,不要使用单引号;
【高】属性名全小写,用中划线做分隔符;
【高】不要在自动闭合标签结尾处使用斜线;
【高】不要忽略可选的关闭标签,例:li和 body
【高】使用标准的HTML5 DOCTYPE声明:<!DOCTYPE html>
正例:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Page title</title>
</head>
<body>
<img src="images/company_logo.png" alt="Company">
<h1 class="hello-world">Hello, world!</h1>
</body>
</html> 【高】HTML注释的语法是以<!--开始,以-->结束,在这两个标记之间的任何内容都被视为注释。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport">
<title>HTML注释示例</title>
<!-- 这是一个HTML注释 -->
<!--
这是一个多行HTML注释
可以跨越多行
并包含任何文本
-->
</head>
</html> 3.3 语义化标签使用※
【高】HTML5 中提供了很多语义化标签,优先使用语义化标签,避免所有页面里全部使用 div 标签的情况。
正例:
<header></header>
<footer></footer> 反例:
<div>
<div></div>
</div> 说明:前端语义化标签的重要性主要体现在以下几个方面:
①提升页面结构清晰度:语义化标签如header , nav , article , section , aside和footer等,能够帮助开发者更好地组织页面结构,使得页面内容更加清晰和有条理,集中体现在以下优势:
②优化搜索引擎优化(SEO):搜索引擎爬虫依赖于HTML标签来确定页面的上下文和关键字权重。使用语义化标签可以使搜索引擎更容易理解页面的内容结构,从而提高页面的搜索排名。
③提升无障碍访问:语义化标签有助于屏幕阅读器等辅助技术正确读取网页内容,使得视觉障碍用户也能更好地访问网站。
④增强代码可读性和维护性:语义化标签能够使代码更加直观,便于团队成员理解和维护,特别是在没有CSS样式的情况下,页面仍然能够正确显示。
⑤兼容性更好:语义化标签能够更好地兼容不同的设备和浏览器,特别是在移动设备和老旧浏览器上,能够提供更好的用户体验。
【中】在旧版本的浏览器中,可能不支持某些HTML5元素,例如header、footer、section等。解决方法是使用HTML5 shiv来使这些元素在旧版本浏览器中也能正常工作:引入方式如图:
正例:
<!--[if lt IE 9]>
<script src="/libs/html5shiv/3.7.3/html5shiv.min.js">
</script>
<![endif]-->3.4 HTML属性顺序规范※
【高】HTML属性应该按照特定的顺序出现以保证易读性;顺序如下所示:
class
id
name
data-src, for, type, href, value , max-length, max, min, pattern
placeholder, title, alt
aria-, role
required, readonly, disabled
说明:class是为高可复用组件设计的,所以应处在第一位;id更加具体且应该尽量少使用,放在第二位。
正例:
<a class="..." id="..." data-modal="toggle" href="#">link_A</a>
<input class="form-control" type="text">
<img src="..." alt="...">
【中】HTML中boolean属性指不需要声明取值的属性
说明:XHTML需要每个属性声明取值,但是HTML5并不需要,boolean属性的存在表示取值为true,不存在则表示取值为false。
正例:
<input type="text" disabled>
<input type="checkbox" value="1" checked>
<select>
<option value="1" selected>1</option>
</select>3.5 HTML标签使用规范※
【中】实用高于完美,在编写HTML代码时,须尽量避免多余的父节点。
正例:
<img class="avatar" src="..."/> 反例:
<span class="avatar">
<img src="..."/>
</span> 说明:尽量遵循HTML标准和语义,但是不应该以浪费实用性作为代价;任何时候都要用尽量小的复杂度和尽量少的标签来解决问题。
4 CSS(SCSS, LESS)编程实践及规范※
4.1 优先选择CSS3※
CSS3的语法建立在CSS原先版本基础上。且允许使用者在标签中指定特定的HTML元素而不必使用多余的class、id或JavaScript
【高】开发者需要考虑不同浏览器对特性的支持情况,对于低版本浏览器(尤其是低版本IE浏览器)。使用前缀或polyfill来确保代码的兼容性,在兼容性明确的情况下进行CSS3的开发。
【高】全部采用小写方式以中划线分隔的命名方式命名CSS文件,避免使用特殊字符和汉字,不能包含空格。
正例:
link.css
style-sheet.css
signup.scss
4.2 代码格式规范※
4.2.1 缩进※
【高】使用soft tab(4个空格)
正例:
.element {
position: absolute;
top: 10px;
left: 10px;
border-radius: 10px;
width: 50px;
height: 50px;
} 4.2.2 分号※
【高】每个属性声明末尾都要加分号
正例:
.element {
width: 20px;
height: 20px;
background-color: red;
} 4.2.3 空格※
【高】以下几种情况不需要空格:
属性名后
多个规则的分隔符','前
!important '!'后
属性值中'('后和')'前
行末不要有多余的空格
【高】以下几种情况需要空格:
属性值前
选择器'>', '+', '~'前后
'{'前
!important '!'前
属性值中的','后
注释'/'后和'/'前
正例:
.element {
color: red !important;
background-color: rgba(0, 0, 0, .5);
}
.element,
.dialog {
}
.element > .dialog{
...
}
.element {
...
} 反例:
.element ,
.dialog{
...
} 4.2.4 空行※
【高】以下几种情况需要空行:
文件最后保留一个空行
'}'后最好跟一个空行,包括LESS,SCSS中嵌套的规则
属性之间需要适当的空行,具体见属性声明顺序
正例:
.element {
...
}
.dialog {
color: red;
```
&:after {
...
}
```
} 反例:
.element {
...
}
.dialog {
color: red;
&:after {
...
}
} 4.2.5 换行※
【高】以下几种情况不需要换行:
'{'前
【高】以下几种情况需要换行:
'{'后和'}'前
每个属性独占一行
多个规则的分隔符','后
正例:
.element {
color: red;
background-color: black;
} 反例:
.element {
color: red; background-color: black;
} 4.2.6 引号※
【高】最外层统一使用双引号,url的内容要用引号,属性选择器中的属性值需要引号。
正例:
.element:after {
content: "";
background-image: url("logo.png");
}
li[data-type="single"] {
...
} 4.2.7 注释规范※
【高】注释统一用/* */(SCSS,LESS中也不要用'//'),具体参照如下写法,缩进与下一行代码保持一致,可位于一个代码行的末尾,与代码间隔一个空格。
正例:
/* Modal header */
.modal-header {
...
}
/*
- Modal header
*/
.modal-header {
...
}
.modal-header {
/* 50px */
width: 50px;
```
color: red; /* color red */
```
} 4.3 选择器命名※
【高】类名使用小写字母,以中划线分隔,
【高】id 采用驼峰式命名
【中】LESS,SCSS中的变量、函数、混合、placeholder 采用驼峰式命名。
说明:id、class的名称总是使用可以反应元素目的和用途的名称,或其他通用的名称,代替表象和晦涩难懂的名称。
反例:
.fw-800 {
font-weight: 800;
}
.red {
color: red;
} 正例:
.heavy {
font-weight: 800;
}
.important {
color: red;
}
/* class */
.element-content {
...
}
/* id */
#myDialog {
...
}
/* 变量 */
$colorBlack: #000;
/* 函数 */
@function pxToRem($px) {
...
}
/* 混合 */
@mixin centerBlock {
...
}
/* placeholder */
%myDialog {
...
} 4.4 选择器编写方式※
【高】CSS选择器中避免使用标签名
从结构、表现、行为分离的原则来看,应该尽量避免CSS中HTML标签的出现,在CSS选择器中出现标签名会存在潜在的问题。
【中】使用直接子选择器
说明:很多前端开发人员写CSS选择器链的时候不使用直接子选择器,从而某些情况下会导致性能的损耗。
反例:
.content .title {
font-size: 2rem;
} 正例:
.content>.title {
font-size: 2rem;
} 4.5 尽量使用缩写属性※
【中】CSS缩写是一种减少代码量并使CSS更加高效的方法。以下是一些常见的CSS缩写属性。
正例:
/* 单一方向的缩写 */
margin-top: 10px;
margin-right: 20px;
margin-bottom: 10px;
margin-left: 20px;
/* 可缩写为 */
margin: 10px 20px 10px 20px; /* 上 | 右 | 下 | 左 */
/* 如果上下边距相同,左右边距相同,可进一步缩写为 */
margin: 10px 20px; /* 上下 | 左右 */
/* 如果四个方向的值都相同,可进一步缩写为 */
margin: 10px; /* 四面都是10px */ 说明:确保缩写属性不会影响代码的可读性和可维护性。在缩写时,要清楚每个值的含义,并确保它们符合预期的表现。
4.6 避免使用id选择器及全局标签选择器※
【中】为了避免使用id选择器及全局标签选择器造成污染全局样式,可以使用更具体的类选择器和嵌套规则。以下是一个简化的CSS样例,展示了如何使用类选择器来提高样式的特异度,从而减少样式污染的风险。
反例:
#header {
padding-bottom: 0px; margin: 0em;
} 正例:
.header {
padding-bottom: 0px; margin: 0em;
} 4.7 避免样式直接写入HTML中,应添加有意义的class等选择器※
【中】为了避免在HTML中直接写入style样式,应该尽可能地使用CSS选择器来添加样式,并且尽可能给元素添加有意义的class或id,以便于后期的维护和理解。
4.8 避免嵌套层级过多※
【中】将嵌套深度限制在 3 级。对于超过 4 级的嵌套,应给予重新评估。这可以避免出现过于详实的CSS选择器,避免大量的嵌套规则,推荐避免出现多于 20 行的嵌套规则出现。
反例:
.main {
.title {
.name {
color: #fff;
}
}
} 正例:
.main {
.title {
color: #fff;
}
} 4.9 代码组织规范※
【高】建议将公共CSS,LESS文件放置在统一目录下。 (less为例: // color.less,common.less 放置在 style/less/common 文件夹)
【高】代码按以下顺序组织
@import ②变量声明 ③样式声明
正例:
@import "mixins/size.less";
@default-text-color: #333;
.page {
width: 960px; margin: 0 auto;
} 4.10 多浏览器兼容性规范※
【高】浏览器前缀用于标记该属性或值仅在特定浏览器或浏览器版本中支持,对于私有属性的顺序要注意把标准写法放到最后,兼容性写法放到前面。
正例:
-webkit-transform:rotate(-3deg); /*为Chrome,Safari*/
-moz-transform:rotate(-3deg); /*为Firefox*/
-ms-transform:rotate(-3deg); /*为IE*/
-o-transform:rotate(-3deg); /*为Opera*/
transform:rotate(-3deg); 5 JavaScript编程实践及规范※
5.1 优先选择ECMAScript 6※
【高】优先使用ECMAScript 6(以下简称ES6)
新建项目优先使用ES6进行编写,将大大简化开发人员的编码过程,并让代码实现更加灵活和可复用。
说明:ES6代码可以通过Babel(一种ES6转码器),转换为ES5代码,从而在现有环境执行。这方便了开发人员使用ES6的方式编写程序,而不用担心现有环境是否支持。
【高】活用中新增的语法糖和函数,比如箭头函数、await/async, 解构赋值, let ,const, for...of 等等,包括但不限于以下几点:
【高】使用字符串模板(``)来拼接字符串,而不是使用加号(+)。
【高】使用数组和对象解构赋值来简化变量赋值。
【高】使用箭头函数(=>)来写简洁的函数。
【高】避免使用全局变量,应该使用const、let来声明变量,特别是在循环引用和修改的情况下。
【高】使用类和模块来组织复杂的代码,并导出、导入功能来管理依赖。
【高】使用Promise和async/await来处理异步代码,而不是回调和then链。
【高】使用const来声明常量,不推荐使用var。
【中】对象属性和数组元素应使用简洁表达法。
【中】推荐使用for...of来代替for...in方式遍历数组和其他可迭代对象。
正例:
// 使用es6 let和const声明变量
let count = 0;
const pi = 3.14;
// 使用es6 字符串模板
const name = 'World';
const greeting = `Hello, ${name}!`;
// 使用es6 箭头函数
const square = (x) => x * x;
// 使用es6 解构赋值
const { log } = console;
// es6 导入模块成员
import { readFile } from 'fs';
// 使用es6 Promise和async/await处理异步操作
async function readFileAsync(filePath) {
try {
const data = await readFile(filePath, 'utf8');
console.log(data);
} catch (error) {
console.error(error);
}
}
// 使用es6 for...of循环
const numbers = [1, 2, 3, 4, 5];
for (const number of numbers) {
console.log(number);
} 5.2 JS代码格式规范※
5.2.1 缩进※
【高】大括号与if,else,for,do,while语句一起使用,即使只有一条语句甚至是空,也应该把大括号写上;如果是大括号内为空,则简洁地写成{ }即可,大括号中间无需换行和空格;如果是非空代码块则:
①左大括号前不换行,后换行。
②右大括号前换行,右大括号后还有else等代码则不换行;表示终止的右大括号后必须换行。
5.2.2 缩进※
【高】每当开始一个新的块,缩进增加4个空格,当块结束时,缩进返回先前的缩进级别,缩进级别适用于代码和注释。
正例:
var x = 1,
y = 1;
if (x < y) {
x += 10;
} else {
x += 1;
} 5.2.2 空格※
【高】采用4个空格缩进,禁止使用Tab字符
说明:如果使用Tab键缩进,必须设置1个Tab为4个空格。
①分隔任何保留字与紧随其后的左括号(()(如if, for catch等)。
②分隔任何保留字与其前面的右大括号(})(如else, catch)。
③左小括号和右边相邻字符之间不出现空格;右小括号和左边相邻字符之间也不出现空格;左大括号前需要加空格。
④任何二目、三目运算符的左右两边都需要加一个空格,包括赋值运算符=、逻辑运算符&&、加减乘除符号等。
⑤注释的双斜线与注释内容之间有且仅有一个空格。
5.2.4 空行※
【高】不同逻辑、不同语义、不同业务的代码之间插入一个空行分隔开来以提升可读性。
说明:任何情形没有必要插入多个空行进行隔开。
5.2.5 分号※
【高】以下几种情况后需加分号:
变量声明
表达式
return
throw
break
continue
do-while
正例:
/* var declaration */
var x = 1;
/* expression statement */
x++;
/* do-while */
do {
x++;
} while (x < 10); 5.2.6 行宽和换行※
【高】单行字符数限制不超过120个,超出需要换行,换行时遵循如下原则:
①第二行相对第一行缩进4个空格,从第三行开始,不再继续缩进,参考示例。
②运算符与下文一起换行。
③方法调用的点符号与下文一起换行。
④方法调用中的多个参数需要换行时,在逗号后进行。
⑤在括号前不要换行,见反例。
正例:
let arr = new Array();
// 超过120个字符的情况下,换行缩进4个空格,并且方法前的点号一起换行
arr.contact("arr1").concat("arr2")
.concat("arr3")
.concat("arr_N"); 反例:
let arr = new Array();
// 超过120个字符的情况下,不要在括号前换行
arr.contact("arr1").contact("arr2").contact
("arr_N");
// 参数很多的方法调用可能超过120个字符,逗号后才是换行处
func(args1, args2, args3, ...
, argsX); 【中】单个方法的总行数不超过80行。
说明:除注释之外的方法签名、左右大括号、方法内代码、空行、回车及任何不可见字符的总行数不超过80行。
5.2.7 注释规范※
【高】团队应该共同制定注释风格规范,并通过代码审查来确保每位成员都遵循这些规范。无论是单行注释、多行注释亦或是JSDoc注释,一致的风格可以使代码更加整洁和专业。
【高】单行注释须符合以下规则:
双斜线后,必须跟一个空格;
缩进与下一行代码保持一致;
可位于一个代码行的末尾,与代码间隔一个空格。
正例:
if (condition) {
// if you made it here, then all security checks passed
allowed();
}
var name = 'zhangsan'; // one space after code 【高】多行注释建议在以下情况下使用:
难于理解的代码段
可能存在错误的代码段
浏览器特殊的HACK代码
业务逻辑强相关的代码
正例:
/*
- one space after '*'
*/
var x = 1; 【高】所有的抽象方法(包括接口中的方法)推荐使用JSDoc注释、除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能。
说明:JSDoc是一种流行的注释规范,它不仅可以提高代码的可读性,还可以被一些工具用来生成文档。在前端项目中,推荐使用JSDoc来注释函数、类和方法。其中:
@param:描述函数或方法的参数。包括参数名、参数类型和参数描述。
@returns 或 @return:描述函数或方法的返回值。包括返回值的类型和描述。
@type:描述变量、对象属性或函数返回值的类型。
@description:提供关于注释块的更详细描述。
@example:提供示例代码。
@see:提供参考链接。
正例:
/**
- 用来计算两个整数之和的方法。
-
- @param a 第一个加数
- @param b 第二个加数
- @return 两个加数的和
*/说明:对子类的实现要求,或者调用注意事项,请一并说明。
【高】所有的枚举类型字段必须要有注释,说明每个数据项的用途。数据库动态维护场景变量注释应描述为码表的类别编码。
【高】建议用中文注释把问题说清楚。专有名词与关键字保持英文原文即可。
反例:
// "TCP连接超时" 错误地解释成 "传输控制协议连接超时",反而不易理解。
【高】代码修改的同时,注释也要进行相应的修改,尤其是参数、返回值、异常、核心逻辑等的修改。
【高】在类中删除未使用的任何字段、方法、内部类,在方法中删除未使用的任何参数声明与内部变量。
【高】谨慎注释掉代码,在上方详细说明,而不是简单地注释掉。如果无用,则删除。
说明:代码被注释掉有两种可能性:
①后续会恢复此段代码逻辑。
②永久不用。前者如果没有备注信息,难以知晓注释动机;后者建议直接删掉即可,假如需要查阅历史代码,登录代码仓库即可。
【中】合理的命名、代码结构是自解释的,注释力求精简准确、表达到位,避免出现过多过滥的注释。
【低】项目中可酌情使用特殊注释
TODO:用于标记需要将来完成或改进的代码部分。FIXME:用于标记需要修复的错误或问题。HACK:用于标记可能不优雅的解决方案。
说明:此类注释只是开发过程中暂时使用,当开发人员对注释的功能进行部分改进、修复完成后必须尽早将该类注释删除。
5.3 命名规范※
【高】变量采用lowerCamelCase方式,即小写驼峰命名,代码中的命名均不能以下划线,也不能以下划线或美元符号结束。
反例:
_name / name_ / name$
【高】在处理深拷贝和浅拷贝时,应明确区分两者的命名,推荐遵循如下原则:
针对深拷贝可以使用"shallowClone"字段加上变量名首字母大写或来命名。
针对深拷贝可以使用"deepClone"字段加上变量名首字母大写或来命名。
正例:
let shallowCloneUsrInfo = { ...usrInfo };
【高】常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不可强行缩写。
正例:
MAX_STOCK_COUNT
反例:
MAX_COUNT
【高】方法名(除构造函数)、参数名、成员变量、局部变量都统一使用lowerCamelCase 风格,必须遵从驼峰形式。
正例:
localValue / getHttpMessage() / inputUserId;
反例:
save / open / show / go
说明:其中 method 方法命名必须是动词或动词+名词的形式 如果涉及到与后台交互相关的,须与后台人员接口风格统一,不得使用其他风格。
【高】构造函数大写第一个字母
正例:
function Car(brand, model) {
this.brand = brand;
this.model = model;
} 5.4 变量声明※
【高】使用字面值创建对象
正例:
let org = {};
反例:
let org = new Object();
【高】使用字面量来代替对象构造器
正例:
let user = {
age: 0,
name: 1,
orgId: 3
}; 反例:
var user = new Object();
user.age = 0;
user.name = 0;
user.orgId= 0; 5.5 前端路由命名规范※
【高】推荐使用英文命名,避免使用中文或特殊字符,确保命名的一致性和可读性。应该满足以下要点:
①唯一性:每个路由名称必须是唯一的,避免重复。
②见名知意:命名应该直观地反映路由的功能或内容,看到名称就能理解其作用。
③简洁明了:尽量使用简短的名称,避免过长的命名。
5.6undefined判断规范※
【高】不要直接使用 undefined 进行变量判断;使用 typeof 和字符串'undefined'对变量进行判断。
正例:
if (typeof person == 'undefined') {
...
}; 反例:
if (person === undefined) {
...
};5.7判断和循环规范
【中】条件判断及循环最多三层
说明:条件判断能使用三目运算符和逻辑运算符解决的,就不要使用条件判断,但是谨记不要写太长的三目运算符。如果超过 3层请抽成函数,推荐用对象映射简化代码,并写清楚注释。对于超过3层的条件判断,用对象映射方法比起传统的if-else 方法和 switch 语句都更加方便。
正例:
function calculateDiscount(loyaltyLevel) {
const discountMap = {
'GOLD': applyGoldDiscount,
'SILVER': applySilverDiscount,
'BRONZE': applyBronzeDiscount
};
discountMap[loyaltyLevel] && discountMap[loyaltyLevel](); 5.8 this的转换命名规范※
【中】对上下文 this 的引用使用'self'来命名。
5.9前端日志规范※
【高】慎用 console.log、console.warn、console.error等前端日志因该类调试日志方法的大量使用会有性能问题,在非webpack 项目中谨慎使用 log,warn,error 功能,尤其在生产环境。
5.10前端请求规范※
【高】前端请求要求使用异步加载方式请求,特殊情况需要同步处理除外。
【高】接口命名与后端接口保持一致。
【高】接口风格:尽量统一风格,禁止单独适配,前端使用axios统一封装请求方法,做统一请求、拦截。
【高】查询类请求使用get方式,入参如果太长请使用post方式请求。
【高】提交相关类请求请使用post方式。
【高】前后端请求传输报文,若存在超大整数Number类型的场景,该字段需要以字符串的方式进行前后端互传,以免传输过程中数字精度的丢失
5.11 JS代码注意事项和最佳实践※
高】使用===,而不是==。
说明:==(或!=)操作符在需要的时候会自动执行类型转换。===(或!==)操作不会执行任何转换。它将比较值和类型,而且在速度上也优于==。
正例:
[10] === 10 // false (正确)
反例:
'' == false // true (输出是true 但是实际上是false)
【高】谨慎使用typeof、instanceof 和 constructor 进行判断
typeof、instanceof和constructor都有其各自的用途和场景。typeof:用来检测数据类型,但对于数组、null和对象的处理不够准确,对于数组和null都会返回"object"。instanceof不能准确判断基本数据类型,它只能用来判断对象类型。constructor:指向创建对象的构造函数,但如果原型链被修改,则可能不再准确,须谨慎使用。
【高】不要使用delete方法来删除一个数组中的项。
说明:使用 splice方法 而不要使用 delete方法来删除数组中的某个项。使用 delete 只是用 undefined来替换掉原有的项,并不是真正的从数组中删除。delete方法应该被用来删除一个对象的某个属性。
【高】避免数组中的负数索引(negative indexes)。
反例:
var array = [1,2,3,4,5];
var from = array.indexOf("foo") ; // from 为 -1
array.splice(from,2); // 错误地返回了5(该数值在arr中并不存在) 【高】避免使用eval()配合Function构造函数。
说明:使用eval方法配合Function构造函数是非常昂贵的操作,因为每次他们都会调用脚本引擎将源代码转换成可执行代码。
反例:
var func1 = new Function(functionCode);
var func2 = eval(functionCode); 【高】避免使用 with()。
说明:使用 with() 会插入一个全局变量。因此,同名的变量会被覆盖值而引起不必要的麻烦。
【高】在调用setTimeout()和setInterval()时传入函数,而不是传入字符串。
说明:如果你将字符串传递给setTimeout()或setInterval(),这个字符串将被如使用 eval一样被解析,这个是非常耗时的。
【中】 尽量避免使用 for-in 方法遍历一个数组。
反例:
var sum = 0;
for (var i in arrayNumbers) {
sum += arrayNumbers[i];
} 正例:
let sum = 0;
for (let i = 0, len = arrayNumbers.length; i < len; i++) {
sum += arrayNumbers[i];
} 【中】尽量避免在循环内部使用try-catch-finally。
说明:在运行时,每次当 catch 从句被执行的时候,被捕获的异常对象会赋值给一个变量,而在 try-catch-finally 结构中,每次都会新建这个变量。
反例:
var object = ['foo', 'bar'], i;
for (i = 0, len = object.length; i <len; i++) {
try {
// do something that throws an exception
}catch (e) {
// handle exception
}
} 正例:
var object = ['foo', 'bar'], i;
try {
for (i = 0, len = object.length; i <len; i++) {
// do something that throws an exception
}
}catch (e) {
// handle exception
} 【中】使用for-in遍历一个对象内部属性的时候注意检查属性。
说明:应用hasOwnProperty方法可以能够避免在遍历一个对象属性的时候访问原型的属性,如下所示。
正例:
for (var name in object) {
if (object.hasOwnProperty(name)) {
// do something with name
}
};【中】合理为XMLHttpRequests 设置超时。
说明:在一个XHR请求占用很长时间后(如由于网络问题),可能需要中止这次请求,那么便可以对XHR调用配套使用setTimeout()。
正例:
var xhr = new XMLHttpRequest ();
xhr.onreadystatechange = function () {
if (this.readyState == 4) {
clearTimeout(timeout);
// do something with response data
}
}
var timeout = setTimeout( function () {
xhr.abort();
// call error callback
}, 60*1000 );
xhr.open('GET', url, true);
xhr.send(); 【中】合理设置 WebSocket 超时。
说明:通常在一个 WebSocket连接创建之后,如果没有活动,服务器会在30秒之后断开(timeout)连接。防火墙也会在一段时间不活动之后断开连接。为了防止超时的问题,客户端需要间歇性地向服务器端发送空消息。为此,可以在代码里添加下面的两个函数:一个用来保持连接,另一个用来取消连接的保持。通过这个技巧,开发人员能够控制超时的问题。
正例:
var timerID = 0;
function keepAlive() {
var timeout = 15000;
if (webSocket.readyState == webSocket.OPEN) {
webSocket.send('');
}
timerId = setTimeout(keepAlive, timeout);
}
function cancelKeepAlive() {
if (timerId) {
cancelTimeout(timerId);
}
} 【中】建议异步编程时使用async/await替代传统回调函数和then(),利于提高代码可读性和可维护性。
正例:
async function asyncFunction() {
try {
let result = await asyncOperation();
// ...
} catch (error) {
// ...
}
} 【中】建议使用import语句引入模块,而不是require。
正例:
import React from 'react';【低】建议保留N位小数toFixed来四舍五入一个数字。
说明:所有的 JavaScript 数字在内部都是以 64位二进制表示的浮点数,开发人员可以使用toFixed()和toPrecision()方法解决这个问题。
正例:
var num = 2.443242342;
num = num.toFixed(4); // num will be equal to 2.4432 【低】合理使用闭包实现私有变量
正例:
function createCounter() {
let count = 0;
return function() {
count++;
console.log(count);
}
}
const counter = createCounter();
counter(); // 输出 1
counter(); // 输出 2 说明:闭包可以捕获并保持对外部变量的引用,使得函数值具有状态和行为,可以在多次调用之间保留状态。但是,使用闭包需要注意手动释放闭包,否则使用不当可能会导致内存泄露,必须谨慎使用。
【低】建议在JS语句结尾处使用分号。多数情况下 JavaScript 解释器会帮助我们加上分号,但是在语句结尾处使用分号更加便于理解。
6 Vue2项目规范※
6.1 Vue2项目规范依据※
Vue2项目以Vue2官方规范中的规范为基础,在其上面进行项目开发,故所有代码应均遵守该规范。
6.2 Vue2组件规范※
【高】组件名为多个单词,且命名规范为 kebab-case 格式。
说明:Vue2代码中的组件名应该始终是多个单词组成(大于等于2),命名规范为 kebab-case 格式。
正例:
export default {
name: 'todo-item',
} 正例:
components/
|- my-component.vue
反例:
components/
|- myComponent.vue
|- MyComponent.vue
【高】基础组件文件名为base开头,使用完整单词而非缩写。
正例:
components/
|- base-button.vue
反例:
components/
|- MyButton.vue
|- VueTable.vue
|- Icon.vue
【高】和父组件紧密耦合的子组件应该以父组件名作为前缀命名。
正例:
components/
|- todo-list.vue
|- todo-list-item.vue
|- todo-list-item-button.vue
|- user-profile-options.vue (完整单词)
反例:
components/
|- TodoList.vue
|- TodoItem.vue
|- TodoButton.vue
|- UProfOpts.vue (使用了缩写)
【高】组件的 data 必须定义为一个函数。
说明:当在组件中使用 data 属性的时候(除new Vue外),它的返回值必须是返回一个对象的函数。因为如果直接是一个对象的话,子组件之间的属性值会互相影响。
【高】Prop 定义应该尽量详细。
①必须使用 camelCase 首字母小写驼峰命名
②必须指定类型
③适当地加上注释,表明其含义
④必须加上required或者default,两者二选其一
⑤如果有业务需要,适当地加上 validator 验证
【高】为组件样式设置作用域。
正例:
<template>
<button class="btn btn-close">X</button>
</template>
<!-- 使用 `scoped` 特性 -->
<style scoped>
.btn-close {
background-color: red;
}
</style> 反例:
<template>
<button class="btn btn-close">X</button>
</template>
<style>
.btn-close {
background-color: red;
}
</style> 【高】如果特性元素较多,应该主动换
正例:
<MyComponent
foo="a" bar="b" baz="c"
foo1="a" bar1="b" baz1="c"
foo2="a" bar2="b" baz2="c"
/> 反例:
<MyComponent foo="a" bar="b" baz="c" foo="a" bar="b" baz="c" foo="a" bar="b" baz="c" foo="a" bar="c" baz="c5"/> 6.3 Vue2 template模板规范※
【中】组件模板中应该只包含简单的表达式。
说明:复杂的表达式则应该重构为计算属性或方法。复杂表达式使得template模板可读性不高。应尽量描述业务逻辑,而非技术相关,复杂表达式可由计算属性替代。
正例:
<template>
<p>{{ normalizedFullName }}</p>
</template>
// 复杂表达式由计算属性替代
computed: {
normalizedFullName: function () {
return this.fullName.split(' ').map(
function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}
} 反例:
<template>
<p>
{{
fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}}
</p>
</template> 6.4 Vue2指令规范※
【高】指令推荐都使用缩写形式,如下所示:
用":" 表示 v-bind:
用"@"表示 v-on:
用"#"表示 v-slot:
正例:
<input @input="onInput" @focus="onFocus"> 6.5 Vue2文件内部标签顺序规范※
【高】单文件组件内标签顺序保持为:
①template标签 ②script标签 ③style标签
正例:
<template>...</template>
<script>...</script>
<style>...</style>反例:
<style>...</style>
<script>...</script>
<template>...</template>
6.6 Vue2 v-for循环注意事项※
【高】必须为 v-for 设置键值 key。
6.7 Vue2 v-show 与 v-if 选择※
【中】如果项目运行时需要非常频繁地切换dom元素则建议使用 v-show;如果在运行时条件很少改变则使用 v-if。
6.18 Vue2 Router 路由规范※
【高】页面跳转数据传递使用路由参数。
说明:例如 A 页面跳转到 B 页面,需要将 A 页面的数据传递到 B页面,推荐使用路由参数进行传参,而不是将需要传递的数据保存 Vuex,然后在B 页面取出 Vuex 的数据,因为如果在 B 页面刷新会导致 Vuex 数据丢失,导致B 页面无法正常显示数据。
正例:
let oid = '123';
this.$router.push({ name: 'orgCenter',query: { orgId: oid } }); 【高】使用路由懒加载(延迟加载)机制。
正例:
{
path: '/uploadAttachment', name: 'uploadAttachment',
meta: { title: '上传附件'},
component:()=> import('@/view/components/uploadAttachment/index.vue')
} 【中】Vue2路由中的path、childrenPoints 命名规范采用 kebab-case 规范。
说明:Vue2路由命名尽量与 Vue文件的目录结构保持一致,因为目录、文件名都是kebab-case,这样很方便找到对应的文件;name 命名规范采用 kebab-case命名规范且和 component 组件名保持一致,因为要保持keep-alive特性,keep-alive 按照 component 的 name进行缓存,所以两者必须高度保持一致。