史上最全前端开发规范

248 阅读11分钟

前言:
规范成就高质量代码

(一)Vue项目目录规范

1.1 基础

项目中所有模块命名与后端命名统一。
例如:
后端:系统管理(system-manage)
前端:无论router,services,views都应使用system-manage

1.2 脚手架

待补充...

1.3 注释说明

整理必须加注释的地方

  • 公共组件使用说明
  • services目录的接口ts,模型(model)ts等必须添加注释
  • store中的state、getters、action等必须添加注释
  • vue文件中的template必须添加注释,若文件较大添加start、end注释
  • vue文件中的每个method必须添加注释
  • 相关ts文件,非常见字段需要添加注释,interface/type 等必须添加注释

1.4 目录说明 [示例]

所有目录均使用kebab-case命名。

|-build				打包配置
|-mock				数据模拟
|-public			公共静态资源目录
|-types				全局变量
|-src				主目录
| |-assets			    静态文件
| |-components			    公共组件
| |-config			    系统配置
| |-constants			    常量/Enums
| |-directives			    自定义指令
| |-hooks			    公共hooks文件
| |-layouts			    布局配置
| |-router			    路由配置
| |-services			    接口服务
|   |-system-manage		        系统管理
|     |-user-manage			用户管理
|       |-model				    数据模型
|       |-index				    数据请求
| |-store			    数据仓库
| |-styles			    样式文件
| |-test			    单元测试
| |-utils			    通用工具类库
| |-views				页面
|   |-components			公用业务组件
|   |-system-manage			系统管理
|     |-user-manage			    用户管理
|       |-children				子页面
|       |-components				业务组件
|       |-hooks					业务hooks
|       |-data.ts				业务变量
|       |-index.vue				业务页面
1)assets目录 [命名格式:kebab-case]

assets为静态资源,存放images、icons等静态资源

|-assets
|-|-icons
|-|-images
|-|-|-background-color.png
|-|-|-upload-header.png
2)components目录 [命名格式:kebab-case]

components存放公共组件,按照组件进行目录划分

|-components
| |-modal
|   |-src
|     |-components
|       |-modal-header.vue
|       |-modal-body.vue
|     |-hooks
|       |-use-modal.ts
|       |-use-modal-drag.ts
|     |-data.ts
|     |-modal.vue
|     |-index.less
|   |-index.ts
3)config目录 [命名格式:kebab-case]

config存放全局公共配置

|-config
| |-component-config.ts
| |-style-config.ts
| |-project-config.ts
4)constants目录 [命名格式:kebab-case]

constants存放项目所有常量/枚举

|-constants
| |-enums
|   |-app-enum.ts
|   |-page-enum.ts
| |-constants
|   |-file-constant.ts
|   |-role-constant.ts
5)directives目录 [命名格式:kebab-case]

directives存放项目自定义指令

|-directives
| |-click-outside.ts
| |-click-repeat.ts
6)hooks目录 [命名格式:kebab-case]

hooks存放公共钩子函数,按照功能目录划分

|-hooks
| |-config
|   |-use-header-config.ts
|   |-use-menu-config.ts
| |-event
|   |-use-event-listener.ts
|   |-use-scroll.ts
|   |-use-window-size.ts
| |-web
|   |-use-copy-paste.ts
|   |-use-message.ts
|   |-use-window-size.ts
7)layouts目录 [命名格式:kebab-case]

layouts存放布局配置

|-layouts
| |-content
|   |-hooks
|     |-use-height.ts
|     |-use-view.ts
|   |-index.vue
| |-header
|   |-components
|     |-header-notify
|       |-data.ts
|       |-index.vue
|   |-hooks
|     |-use-footer.ts
|   |-index
8)router目录 [命名格式:kebab-case]

存放页面路由配置,非动态权限模式下,根据菜单目录进行划分

|-router
| |-guard
|   |-index.ts
|   |-menu-params.guard.ts
|   |-permission-guard.ts
| |-helper
|   |-menu-helper.ts
|   |-route-helper.ts
| |-routes
|   |-moudules
|     |-system-manage.ts
|   |-index.ts
9)services目录 [命名格式:kebab-case]

存放接口服务信息,目录按照业务进行划分

| |-services			    接口服务
|   |-system-manage		        系统管理
|     |-user-manage			用户管理
|       |-model.ts		            数据模型
|       |-index.ts			    数据请求
10)store目录 [命名格式:kebab-case]

存放数据状态,目录按照业务进行划分

|-store
| |-moudules
|   |-permission.ts
|   |-user.ts
| |-index.ts
11)styles目录 [命名格式:kebab-case]

styles存放公共样式文件,根据功能目录划分

|-styles
| |-component
|   |-button.less
|   |-input.less
| |-layout
|   |-color.less
|   |-theme.less
12)tests目录 [命名格式:kebab-case]

待补充...

13)utils目录 [命名格式:kebab-case]

存放公共工具钩子函数

|-utils
| |-cache
|   |-memory-cache.ts
|   |-storage-cache.yts
| |-event
|   |-index.ts
| |-dom
|   |-index.ts
14)views目录 [命名格式:kebab-case]

命名与UI菜单目录保持一致

|-views
| |-components			公用业务组件
| |-system-manage			系统管理
|   |-user-manage			    用户管理
|     |-children				子页面
|     |-components				业务组件
|     |-hooks					业务hooks
|       |-data.ts				业务变量
|     |-index.vue				业务页面

(二) 命名规范

2.1 项目命名 [命名格式:kebab-case]

全部采用小写方式,以中线分隔
正例:basic-web
反例:BasicWeb

2.2 目录命名 [命名格式:kebab-case]

以中线分隔,有复数结构时,要采用复数命名法,缩写不用复数
正例:scripts/styles/components/demo-scripts/img/doc
反例:script/style/demo_scripts/demoStyles/DemoStyles

2.3 TS、JS、CSS、PNG 文件命名 [命名格式:kebab-case]

正例:user-model.ts/data.ts/company-logo.png 反例:userModel.ts

2.3 命名严谨性

代码中的命名严禁使用拼音和英文混合的方式,应该让阅读者易于理解
杜绝完全不规范的缩写!!!
反例:AbstractClass “缩写”命名成 AbsClass;condition “缩写”命名成 condi,此类随意缩写严重降低了代码的可阅读性。

(三) CSS规范

3.1 命名

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

推荐:

.heavy {
  font-weight:800
}
.header-background {
    background-color:#d2d2d2
}

不推荐:

.fw-800 {
  font-weight:800
}
.gray {
    background-color:#d2d2d2
}

3.2 选择器

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

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

2) 使用直接子选择器

推荐:

.contest > .title {
    font-size: 16px;
}

不推荐:

.contest .title {
    font-size: 16px;
}

3) 尽量使用缩写属性

不推荐:

font-size:100%
lint-height: 1.6
padding-bottom: 12px;
padding-left: 6px;
padding-right: 6px;
padding-top: 0px;

推荐:

font: 100%/1.6;
padding: 0 6px 12px;

4) 每个选择器及属性独占一行

.submit-button {
    padding: 0 6px 12px;
    color: #f2f2f2;
}

5) 避免使用id选择器及全局标签选择器防止污染全局样式

推荐:

.header-background {
    background-color:#d2d2d2
}

不推荐:

#header-background {
    background-color:#d2d2d2
}

6) less/scss 使用规范

引入less文件方式:
@import "mixins/size.less"
变量声明:
@default-text-color: #d2d2d2
样式声明:

.page {
    width: 960px;
    margin: 0 auto;
}

层级嵌套:将嵌套深度限制在3级。超过4级的嵌套,应重新评估

(四) TS/JS规范

4.1 命名

1) 采用小写驼峰命名[lowerCamelCase],代码中的命名均不能使用下划线

反例:_name/name_

2) 方法名、参数名、成员变量、局部变量统一使用小驼峰风格

正例:localValue/getHttpMessage()

3) interface、type、枚举统一使用大驼峰风格

正例:HttpEnum、interface UserInfo、type RoleInfo

4.2 编码示例

1) 基本类型

  • 类型声明
    • 通过类型声明可以指定 TS 中变量(参数、形参)的类型
    • 指定类型后,当为变量赋值时,TS 编译器会自动检查值是否符合类型声明,符合则赋值,否则报错
  • 语法
    • let 变量: 类型;
      
      let 变量: 类型 = 值;
      
      function fn(参数: 类型, 参数: 类型): 类型{
          ...
      }
      
  • number
    • let decimal: number = 6
  • boolean
    • let isDone: boolean = false
  • string
    • let color: string = "blue"
  • 字面量
    • let color: 'red' | 'blue' | 'black'
  • any [不建议使用]
    • let d: any = 4
      d = 'abc'
      d = false
      
  • unknown
    • let notSure: unknown = 4
      notSure = 'hello'
      
  • void
    • let unusable: void = undefined
      
  • never
    • function error(message: string): never {
      throw new Error(message);
      }
      
  • array
    •  let numberList: number[] = [1,2,3]
      
  • tuple
    •  let x: [string, number]
       x = ['abc',123]
      

2) class

  • 定义类
   class 类名 {
      属性名: 类型;

      constructor(参数: 类型){
         this.属性名 = 参数;
      }

      方法名(){
         ....
      }

   }
  • 示例
  class Person {
      name: string;

      constructor(name: string){
          this.name = name;
      }

      getName() {
          console.log(`上海飞未${this.name}`)
      }
  }
  • 使用类
   const person = new Persion('信息技术')
   person.getName();
  • 继承类
   class Persion{
       name: string;

       constructor(name: string){
           this.name = name;
       }
   }

   class ManPersion extends Persion{

       bark(){
           console.log(`${this.name}是个程序员!`);
       }
   }

   const manPersion = new ManPersion('小明')
   manPersion.bark();

3) Interface

  • 示例
    interface Person{
        name: string;
        sayHello():void;
    }

    class Student implements Person{
        constructor(public name: string) {
        }

        sayHello() {
            console.log('大家好,我是'+this.name);
        }
    }

4.3 编码规范

1) 环境

TypeScript 文件使用 .ts 扩展名。含 JSX 语法的 TypeScript 文件使用 .tsx 扩展名

2) 文件

在文件结尾处,保留一个空行

3) 命名 【大驼峰】

interface HeaderStateProps {
    // ...
}

interface HeaderDispatchProps {
    // ...
}

type HeaderProps = HeaderStateProps & HeaderDispatchProps

4) 变量 [使用 const 声明 枚举]

const enum Directions { 
    UP, 
    DOWM, 
    LEFT, 
    RIGHT 
}

5) 类型

1、不应显式声明可以自动推导的类型 推荐:

let shouldUpdate = false

不推荐:

let shouldUpdate: boolean = false

6) 使用 as 进行类型声明转换,不使用<>

const root = document.getElementById('root') as HTMLDivElement;

7) 循环

建议使用 Object.keys / Object.values / Object.entries / Object.getOwnPropertyNames 遍历对象,不使用 for .. in

Object.keys(obj).forEach(key => /* ... */)

8) 局部异常处理

  • 在代码会出现异常的地方,使用try / catch进行异常捕获
  • async / await 异步请求
    • 使用async / await 配合使用,使用try / catch进行异常捕获
    • 使用async,不使用await,应在方法后使用catch进行异常捕获 【不推荐】
  /**
   * 异步请求异常捕获
   */
  const testAsyncError = async () => {
    console.log(errorRes)
    return 'text async error'
  }
  
  /**
   * 使用async,不使用await 【不推荐】
   */
  testAsyncError()
  .then((res) => {
    // errorRes 不存在
    console.log(errorRes)
  })
  .catch((error) => console.log(error, 'error'))
  
  /**
  * async/await,使用try/catch进行异常捕获
  */
  const getTestAsyncError = async () => {
    try {
      await testAsyncError()
    } catch (error) {
      console.log(error, 'error')
    }
  }
  • 应避免太过串行处理,示例:

  /**
   * 异步请求-1
   */
  const getAsyncFunOne = async () => {
    // TODO: 逻辑
    console.log('getAsyncFunOne')
  }

  /**
   * 异步请求-2
   */
  const getAsyncFunTwo = async () => {
    // TODO: 逻辑
    console.log('getAsyncFunTwo')
  }

  /**
   * 初始化加载 -- 【不推荐】
   */
  const getInitData = async () => {
    const resultOne = await getAsyncFunOne()
    const resultTwo = await getAsyncFunTwo()
    return {
      oneInfo: resultOne,
      twoInfo: resultTwo
    }
  }

  /**
   * 初始化加载 -- 【推荐】
   */
  const getInitData = async () => {
    const resultOnePromise = getAsyncFunOne()
    const resultTwoPromise = getAsyncFunTwo()

    const resultOne = await resultOnePromise
    const resultTwo = await resultTwoPromise
    return {
      oneInfo: resultOne,
      twoInfo: resultTwo
    }
  }

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

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

3) 常量命名全部大写,单词间用下划线隔开

(五) 注释规范

注释的目的:
提高代码可读性,从而提高代码的可维护性
注释的原则:
如无必要,勿增注释
如有必要,尽量详尽

5.1 HTML 文件注释

5.1.1 单行注释

一般用于简单描述,例如 某些状态或属性描述
注释内容前后各一个空格字符,注释位于注释代码上部,单独占一行

<!-- 注释内容 -->
<div>...</div>

5.1.2 模块注释

一般用于描述模块的名称以及模块开始与结束的位置
注释内容前后各一个空格字符,模块与模块之间相隔一行
<!-- 注释描述 start -->表示模块开始,<!-- 注释描述 end -->表示模块结束

<!-- 模块a start -->
<div class="module-a">...</div>
<!-- 模块a end -->

<!-- 模块b start -->
<div class="module-b">...</div>
<!-- 模块b end -->

5.2 CSS 文件注释

5.2.1 单行注释

注释内容前后各一个空格字符,单独占一行

<!-- 注释内容 -->
.header-banner {...}

5.1.2 模块注释

一般用于描述模块的名称以及模块开始与结束的位置
注释内容前后各一个空格字符,模块与模块之间相隔一行
<!-- 注释描述 start -->表示模块开始,<!-- 注释描述 end -->表示模块结束

/** 
* 模块a
*/
.module-a { ... }

/** 
* 模块b
*/
.module-b { ... }

5.3 TS/JS 文件注释

5.3.1 单行注释

单行注释使用 //,注释应单独一行写在被注释对象上方,不要追加在某条语句后

// 单行内容注释
const active = true

方法内注释行上方需要一个空行,增加代码可读性

const getName = () => {
    console.log('进入方法内')
    
    // 逻辑描述
    ....
    
    return ...
}

5.3.2 多行注释

多行注释使用 /** ... */,而不是多个 //

/**
* 获取名称....
*/
const getName = () => {
    console.log('进入方法内')
    
    // 逻辑描述
    ....
    
    return ...
}

5.3.3 特殊标记

有时我们发现某个可能的Bug,或者某个地方有些待完成的功能,这时我们需要特殊的注释标记来提醒

  • // FIXME:说明问题是什么
  • // TODO:说明还要做什么或问题解决方案
/**
* 获取名称....
*/
const getName = () => {
    console.log('进入方法内')
    
    // FIXME:这里应该判断对象是否为空
    userInfo.name = '...'
    // TODO:这里应该使用传参处理
    const isObject = ...
    
    return ...
}

5.3.4 文档类注释

文档类注释,如:函数、类、文件、事件 等

/**
* 方法描述
* param title:参数名称
* param author:参数名称
* returns 返回描述信息
*/
const getBook = (title:string,author:string) => {
...
}

(六) 提交规范

  • 提交的内容要保持原子性,也就是对于一个功能或者模块,至少要保证单元测试可以跑通并且没有代码报红
  • 代码扫描插件检查代码

6.1 提交格式

$ git commit -m "commit message":message格式为:提交类型模块名称):提交内容描述
注意: 冒号后面有一个空格

提交类型描述
feat新功能(feature),表示从无到有,新增的功能
fix修补bug
docs文档(documentation)
style格式(不影响代码运行的改动)
refactor重构(既不是新增功能,也不是修改bug的代码改动),或者增强逻辑功能
test增加测试,一般是单测和功能代码一起提交用feat,但若后面补一些单测,用这个
chore构建过程或辅助工具的变动,比如:pom、Dockfile等文件的改动

(七) 蓝湖使用规范

  • 原则上应严格按照UI设计图进行还原,有异议时,应及时和UI团队进行沟通
  • 切图下载
    • 纯静态图:不存在颜色变化时,使用png格式
    • 动态图:例如 hover、click、activite等行为时,切图仅颜色发生改变,使用svg格式