前言:
规范成就高质量代码
(一)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进行异常捕获
【不推荐】
- 使用async / await 配合使用,使用
/**
* 异步请求异常捕获
*/
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格式
- 纯静态图:不存在颜色变化时,使用