1.概述

1.1简述

  1. JavaScript编程规范的目的是确保代码的一致性、健壮性以便易于阅读和维护。<br /> 首先阐述下为什么代码规范是重中之重的问题。代码规范并非因为存在而重要,他的主要目的是确保代码对于开发者而言易于阅读和理解。好的代码,并非仅仅对其作者来说易于阅读和理解,而是其他的开发者也能够快速清晰地理解这些代码。高质量的代码能够帮助我们降低维护和更新成本,确保代码是符合项目要求的。

1.2目标群体

此文档的目标群体是为侃度从事JavaScript项目开发和维护的软件工程师。

1.3范围

此文档适用于所有侃度的以JavaScript为编程语言开发的软件项目。

1.4约束性

此规范的约束性用语言描述如下:
-Must: 必须遵守该规范。该规范针对的的内容将接受检查和审核。
-Should:应该遵守该规范。该规范针对的内容将接受检查。
-Can: 这些规范旨在提高质量,无强制的标砖。该规范针对的内容将不接受检查。

1.5质量标准

代码质量的评判标准如下:
-易读性: 对于开发人员的阅读和理解代码的要求应保持最低。
-可维护性:对于开发人员理解代码更新的要求应保持最低。
-稳定性: 软件能够在特定环境下维持性能水平
-高效性: 软件具有高性能水平。
-受测试性:一语惊醒软件的功能性测试。
-受支持性:维护代码能够快速的追踪错误和其产生的原因。

以下是额外的常规性要求:
可审查性: 代码必须格式化并且结构合理,以符合最低限度的审核要求。
符合手工审查要求:代码需要通过手工审查。
符合自动审查要求:代码需通过 代码审查工具的检验。

2.项目规范

本章定义了侃度的JavaScript项目规范

2.1文件夹、组件命名规范,组件结构规范

2.1.1文件夹:

文件夹名称应统一格式,小写开头,见名知意,page页面下的文件夹名称统一以page结尾,
例如:homePage,loginPage。其余文件夹名称统一按照项目结构目录命名规范统一命名。

2.1.2.组件:

约束性 规范 质量标准 审查
Should 当多个单词拼写成的组件时,采用驼峰式命名规则。一般是多个单词全拼,减少简写的情况,这样增加可读性。 可读性
易维护性
手工
Should 组件应该都放到components文件夹下,单个页面独立一个文件夹,用来放相对应的vue文件以及页面相关的样式文件,样式少可直接写到页面组件里边,这样更符合组件化的思想。
公用组件应该统一放到public文件下。
可读性
易维护性
手工

2.1.3基础组件:

约束性 规范 质量标准 审查
Should 当项目中需要自定义比较多的基础组件的时候,比如一些button,input,icon,建议以一个统一的单词Base开头,或者放到base文件夹统一管理,这样做的目的是为了方便查找。 稳定性
可读性
易维护性
手工
Should 页面级组件应该放到相对应页面文件夹下,比如一些组件只有这个页面用到,其他地方没有用到的,可以直接放到页面文件夹,然后以父组件开头命名,例如:HomeHeader.vue,HomeNav.vue。 稳定性
可读性
易维护性
手工
Should 项目级组件一般放到公共文件夹public下给所有的页面使用。 稳定性
可读性
易维护性
手工

2.1.4.组件结构:

组件结构遵循从上往下template,script,style的结构。

  1. <template>
  2. <!--
  3. view代码
  4. -->
  5. </template>
  6. <script>
  7. export default {
  8. /*
  9. sript代码
  10. */
  11. };
  12. </script>
  13. <style scoped>
  14. /*
  15. css代码
  16. */
  17. </style>

3.组件样式

单个组件样式一般可直接写到组件下style标签下,为了防止样式污染,可添加scoped 属性,也可以通过设置作用域来防止样式污染,写样式的时候尽量少写元素选择器,为了提高代码查找速度,可以用类选择器。

4.文件格式

UTF-8格式

5.Template模板文件

约束性 规范 质量标准 审查
Must 尽量使用以.vue结束的单文件组件,方便管理,结构清晰。 易读性 手工
Should 标签语义化,避免清一色的div元素 易读性 手工
Should .多特性,分行写,提高可读性。即一个标签内有多个属性,属性分行写。 易读性 手工
Must 自定义标签:使用自闭标签的写法。如果自定义标签中间需要传入slot,则写开始标签和结束标签,结束标签必须加/。 易读性
可维护性
稳定性
手工+自动
Should 组件/实例选项中的空行。便于阅读和代码架构清晰。 易读性 手工
Must 不得在标签中写入style属性 可维护性
稳定性
手工

6.Script

在 script 标签中,应该遵守Js的规范和ES6规范。

约束性 规范 质量标准 审查
Must Props定义:提供默认值,使用type属性校验类型,使用props之前先检查prop是否存在 可维护性
受支持性
手工
Must 调试信息 console.log() debugger使用完及时删除。 可维护性
受支持性
稳定性
手工+自动
Must 为v-for设置Key值。
可维护性
受支持性
自动
Should 无特殊情况不允许使用原生API操作dom,谨慎使用this.$refs直接操作dom。 可维护性
受支持性
手工
Must 使用ES6风格编码源码,定义变量使用let,定义常量使用const,使用export,import模块化。 可维护性
受支持性
易读性
手工
Must 指令缩写:都用指令缩写 (用 : 表示 v-bind: 和用 @ 表示 v-on:)。 可维护性
受支持性
易读性
手工
Must 使用 data 里的变量时请先在 data 里面初始化。 可维护性
受支持性
易读性
自动
Must 函数中统一使用_this=this来解决全局指向问题。 可维护性
受支持性
易读性
自动
Must 能用单引号不用双引号。 可维护性
受支持性
易读性
自动
Must 尽量使用===而不是==。 可维护性
受支持性
易读性
自动
Must 声明变量必须赋值。 受支持性 自动

7.Style

约束性 规范 质量标准 审查
Must 使用 scoped关键字,约束样式生效的范围。 可维护性
受支持性
易读性
手工
Must 避免使用标签选择器(效率低、损耗性能)。 可维护性
受支持性
易读性
手工
Must 非特殊情况下,禁止使用 ID 选择器定义样式。有 JS 逻辑的情况除外。
CSS 属性书写顺序:先决定定位宽高显示大小,再做局部细节修饰!推荐顺序:定位属性(或显示属性,display)->宽高属性->边距属性(margin, padding)->字体,背景,颜色等,修饰属性的定义。
受支持性 手工

8.注释规范

注意在注释的前后各有一个空格。

8.1使用范围

1.HTML
2.CSS
3.Script
4.Markdown

8.2使用方法

a) 单行注释:// 所有全局变量 data() | vuex等属性 Must
b) 多行注释:/ / 所有函数非生命周期函数 Must

  1. /*
  2. * 所有函数非生命周期函数 Must
  3. */

4.JS注释:
a) 行级注释(注意//后面空格):// 正确的注释
b) 变量声明注释:如果是在类似 Vue 项目的 data 属性中的变量,直接用行级样式跟在后面。
例如:rightExample: ‘yes’, // 注释直接写这里Must
c) 如果是在类,构造函数,或者常量定义中的变量,使用块级注释。Must

  1. /*
  2. * 错误码常亮定义
  3. * @type {number}
  4. */

d) 复杂的业务逻辑处理说明、特殊情况的代码处理说明,对于特殊用途的变量、存在临界值、使用了某种算法思路进行注释说明Must

9.资源路径的配置、引入规则

1.路径配置

  1. build/webpack.base.conf.js文件中配置。
  2. alias: {
  3. ‘@’: resolve(‘src’), // 默认配置,设置src目录别名
  4. childRouter’: resolve(‘src/pages/menuRouter’), // 子路由路径配置
  5. ‘#’: resolve(‘src/assets’) // 配置assets文件夹路径
  6. }

2.路径导入
a) Js文件中导入实例:

约束性 规范 质量标准 审查
Must 导入node_modules模块中的文件,直接引入即可,不需要加文件后缀名。 受支持性 自动
Must 导入自定义文件的时候,使用相对路径或者使用路径配置别名,不许要加文件后缀名。 受支持性 自动
Must 导入node_modules模块:import Vue from ‘vue’ 受支持性 自动
Must 导入自定义文件:import router from ‘./router’import scrollConfig from ‘#/js/vuescroll.config’ 受支持性 自动

b) css或者stylus样式导入需要使用 ~@ 开头

  1. @import ‘~common/stylus/variable

10.数据中心

约束性 规范 质量标准 审查
Should 各个文件的命名根据上面的项目结构命名。 可维护性
易读性
手工
Should 应用层级的状态应该集中到单个 store 对象中。 可维护性
易读性
手工
Should action和mutation中的函数统一声明在mutation-type.js内。 可维护性
易读性
手工
Should mutation-types里面的常量、常量值全部用大写+英文单词配合下划线的形式:例如:export const UPDATE_USERINFO = “UPDATE_USERINFO”。 可维护性
易读性
手工
Should 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。 可维护性
易读性
手工
Should 异步逻辑都应该封装到 action 里面。 可维护性
易读性
稳定性
受支持性
手工
Should vuex 的dispatch和commit提交mutation的区别:dispatch=>actions用来触发异步操作,commit=>mutation用来触发同步操作的方法。当操作行为中含有异步操作,比如向后台发送请求获取数据,就需要使用action的dispatch去完成,其他使用commit即可。 可维护性
易读性
稳定性
受支持性
手工

11.路由

1.路由至少包含三个选项:path、name、component。path统一小写;name对应于组件中的name,大写开头驼峰;component组件名称大写开头的组件驼峰。

  1. {
  2. path: '/',
  3. name: 'HelloWorld',
  4. component: HelloWorld
  5. }

2.一级路由统一使用相对路径的形式。二级路由可以配置,配置见资源路径的配置、引入规则。

  1. {
  2. path: '/',
  3. name: 'HelloWorld',
  4. component: HelloWorld,
  5. children:[
  6. {path:'/detail',
  7. name:'Detail'
  8. component:Detail,
  9. }
  10. ]
  11. }

12.axios

约束性 规范 质量标准 审查
Must 根据需要配置post、get请求,一个是取一个是贴,只需要读取文件,put(PUT 往服务器上上传文件)、delect(删除)直接对数据进行操作相对不安全 。 安全性 手工
Should axios的挂载:Vue.prototype.$http = axios; 可维护性
易读性
稳定性
受支持性
自动
Should axios使用封装后的get/post请求。 可维护性
易读性
稳定性
受支持性
自动
Should ajax的判断
首先 ajax 请求可以写在 actions也可以直接写在 .vue 页面里。
我们判断的依据是回调是否需要调用页面结构来区分,
比如在.vue页面中发送完请求后需要调用 this.$refs.element等,或者需要利用组件的独立性的效果时 后,那就写在.vue页面,否则就写在 actions 里。
可维护性
易读性
稳定性
受支持性
自动

13.api管理

  1. 新建src/ network/api.js
    放置api路径,要注意 axios已经有了前缀,所以这里的 api 值需要写前缀之后的路径。当路径较多时可以再多建几个文件,分类放置。
    例如:
    1. // 统一管理接口
    2. export default {
    3. manage: {
    4. fertilizerStation: '/api/AllFertSiteNameList', // 获取列表
    5. userLogin: '/api/Login' // 用户登录
    6. }
    7. }

2.挂载
在main.js中引入:import api from ‘./request/api’。
使用Vue.prototype.api = api挂载到原型链上即可处处使用。

14.依赖规范

  1. 在package.json里增加包依赖
    1. dependencies”: {
    2. "axios": "^0.18.0"
    3. }

    15.Web字体规范

    | 约束性 | 规范 | 质量标准 | 审查 | | —- | —- | —- | —- | | Should | 优先使用框架中的字体图标,比如element ui中的 | 稳定性 | 手工 | | Should | 使用iconfont字体图标代替图片
    woff: WOFF (Web Open Font 格式)
    ttf: TrueType
    ttf, otf: OpenType
    eot: 嵌入式 OpenType
    svg, svgz: SVG 字体 | 稳定性 | 手工 | | Must | 字体规则
    a) 为了防止文件合并及编码转换时造成问题,建议将样式中文字体名字改成对应的英文名字,如:黑体(SimHei)、宋体(SimSun)、微软雅黑(Microsoft Yahei)。
    b) 字体粗细采用具体数值,粗体bold写成700,正常normal写成400。
    c) font-size必须以px为单位。
    为了对font-family取值进行统一,更好的支持各个操作系统上各个浏览器的兼容性,font-family不允许在业务代码中随意设置。 | 稳定性 | 手工 |

16.各类符号规范

双引号“ “ 中用单引号 ‘ ‘ 可以不用加反斜杠,例如:

  1. var x="my name 'is' xxx" // 此处不需要加反斜杠

双引号“ “ 中用双引号 “ “ 需要加反斜杠,例如:

  1. var x="my name \"is\" xxx" // 此处需要在两个上引号前各加一个加反斜杠

单引号 ‘ ‘ 中用双引号“ “ 不需要加反斜杠,当然加了也可以,例如:

  1. var x1 ='my name "is" xxx' // 此处不需要加反斜杠(推荐)
  2. var x2 ='my name \"is\" xxx' // 添加反斜杠效果也一样(不推荐)

反引号:ES6 模板字符串(Template String)是增强版的字符串,用反引号(`)标识,它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

  1. // 字符串中嵌入变量
  2. var name = "Bob", time = "today";
  3. `Hello ${name}, how are you ${time}?`
约束性 规范 质量标准 审查
Shuold 左大括号前不换行有空格; 易读性
受支持性
手工
Shuold 左大括号后换行 易读性
受支持性
手工
Shuold 右大括号前换行 易读性
受支持性
手工
Shuold 右大括号后还有else等代码则不换行 易读性
受支持性
手工
Shuold 表示终止的右大括号后必须换行。 易读性
受支持性
手工
Shuold 左右小括号与中间字符之间不出现空格 易读性
受支持性
手工
Shuold 逗号:同行逗号后面加空格以隔开 易读性
受支持性
手工

17.命名规范

17.1组件命名

  • 有意义的: 不过于具体,也不过于抽象
  • 简短: 2 到 3 个单词
  • 具有可读性: 以便于沟通交流

    注意事项

    1. <!-- 推荐 -->
    2. <app-header></app-header>
    3. <user-list></user-list>
    4. <range-slider></range-slider>
    5. <!-- 避免 -->
    6. <btn-group></btn-group> <!-- 虽然简短但是可读性差. 使用 `button-group` 替代 -->
    7. <ui-slider></ui-slider> <!-- ui 前缀太过于宽泛,在这里意义不明确 -->
    8. <slider></slider> <!-- 与自定义元素规范不兼容 -->

17.2命名规则

  • 常量大写
  • 避免单字母命名。命名应具备描述性。
  • 【强制】代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。

    1. // bad
    2. function q() {
    3. // ...stuff...
    4. }
    5. // good
    6. function query() {
    7. // ..stuff..
    8. }
  • 使用驼峰式命名对象、函数和实例。

    1. // bad
    2. const OBJEcttsssss = {};
    3. const this_is_my_object = {};
    4. function c() {}
    5. // good
    6. const thisIsMyObject = {};
    7. function thisIsMyFunction() {}

    17.3函数注释规范

  • 函数描述使用 description

  • 参数使用 param
  • 注明返回的类型和值
  • 公共组件使用说明
  • 各组件中重要函数或者类说明
  • 复杂的业务逻辑处理说明
  • 特殊情况的代码处理说明,对于代码中特殊用途的变量、存在临界值、函数中使用的 hack、使用
  • 了某种算法或思路等需要进行注释描述
  • 多重 if 判断语句
  • 注释块必须以/(至少两个星号)开头/
  • 单行注释使用// ```javascript /**
    • @description post请求不进行result过滤
    • @param {string} url 请求的url
    • @param {string} body 请求体
    • @param {boolean} isUserId 是否需要userid
    • 返回rxjs流 */ postRxNormal(url?: string, body: any = {}, isUserId: Boolean = true ): Observable { if (isUserId) { body[‘user_id’] = this.storage.getStorage(‘user_id’); } return this.httpClient.post(url, body); }

/**

  • @description 设置 localStorage
  • @param value 需要存的值
  • @param key 需要存key名字 */ setStorage(value: any, key: string) { try { // 把里面的值转换成json对象 value = JSON.stringify(value); } catch (e) { // 抛出一个错误 value = value; } this.store.setItem(key, value); } ```

    17.4 变量命名

  • 对所有的引用使用 const ;不要使用 var。
  • 如果你一定需要可变动的引用,使用 let 代替 var。

    17.5对象

    17.5.1使用字面值创建对象。

    1. // bad
    2. const item = new Object();
    3. // good
    4. const item = {};

    17.5.2使用对象方法的简写。

    1. // bad
    2. const atom = {
    3. value: 1,
    4. addValue: function (value) {
    5. return atom.value + value
    6. }
    7. };
    8. // good
    9. const atom = {
    10. value: 1,
    11. addValue(value) {
    12. return atom.value + value
    13. },
    14. }

    17.5.3使用对象值的简写

  1. const lukeSkywalker = 'Luke Skywalker'
  2. // bad
  3. const obj = {
  4. lukeSkywalker: lukeSkywalker,
  5. }
  6. // good
  7. const obj = {
  8. lukeSkywalker
  9. }

17.6.字符串

  • 字符串连接使用模板字符串
  1. // bad
  2. function sayHi(name) {
  3. return 'How are you, ' + name + '?';
  4. }
  5. // bad
  6. function sayHi(name) {
  7. return ['How are you, ', name, '?'].join();
  8. }
  9. // good
  10. function sayHi(name) {
  11. return `How are you, ${name}?`;
  12. }

17.7函数

  • 全部函数 第一个名称全部是动词
  • 使用函数声明代替函数表达式。
  1. // bad
  2. const foo = function () {
  3. };
  4. // good
  5. function foo() {
  6. }

17.8构造器

  • 总是使用 class。避免直接操作 prototype
  1. // bad
  2. function Queue(contents = []) {
  3. this._queue = [...contents]
  4. }
  5. Queue.prototype.pop = function() {
  6. const value = this._queue[0]
  7. this._queue.splice(0, 1)
  8. return value
  9. }
  10. // good
  11. class Queue {
  12. constructor(contents = []) {
  13. this._queue = [...contents]
  14. }
  15. pop() {
  16. const value = this._queue[0]
  17. this._queue.splice(0, 1)
  18. return value
  19. }
  20. }

18 设计规范

严格遵循阿里 Ant Design 设计规范 建议使用 Ant Design For Vue Should