# 开发规范
编码规范好比协议,有了 Http
、TCP
等各种协议,计算机之间才能有效地通信,同样的,有了一致的编码规范,开发人员之间才能有效地合作
为提高软件开发质量,降低开发周期,增强代码的可重用性和易读性,使软件便于维护及移交,开发人员间便于交流和协作,本规范适用于前端团队,以作参考。
注意
开发规范执行情况将会不定期进行 Code Review,不符合规范的内容必须进行整改。
# VSCode 插件
为了使开发过程控制,错误提醒以及语法规范在代码编写过程中得到有效提醒及控制,若使用 VSCode 则建议安装以下插件
- ESLint
- HTML Snippets
- IntelliSense for CSS class names in HTML
- JavaScript (ES6) code snippets
- JavaScript standardjs styled snippets
- npm
- npm Intellisense
- Prettier - Code formatter
- Sass
- StandardJS - JavaScript Standard Style
- Todo Tree
- Vetur
- Vue 2 Snippets
# 文件与目录命名规范
前端开发规范应用于 Web 网站、管理平台、移动端内嵌、微信小程序等范围,即使是本文档项目(doc-press
)中的文件命名,依然建议应用本规范
命名规范优秀的行业范例可参考 Vuejs (opens new window) 和 Reactjs (opens new window) 的源码
# 目录命名
业务功能结构示例
├─用户管理
└─授权管理
├─角色管理
└─用户角色绑定
目录命名示例
✖
├─userManage
└─userAuthManage
├─RoleManage
└─userRoleBind
✔
├─user
└─auth
├─role
└─user-role
目录的命名,应尽可能结合上下、父子结构进行上下文信息描述,目录名自身应尽可能简洁直观。文本上使用全小写字母,有词组的情况使用 “-” 符号隔开
# 为什么要使用小写?
易用性/可读性
小写文件名通常比大写文件名更易读,比如accessibility.txt
就比ACCESSIBILITY.TXT
易读。即使使用驼峰命名法,如UserRoleBind
或userRoleBind
不如user-role-bind
的可读性高兼容性
不同操作系统对于大小兼容程度不一样,为了保证编译、部署后的内容在所有平台上顺利部署,目录名也应当使用小写行业惯例
诸如Java
、.net
、C
等著名语言的包路径均为小写,行业巨头的良好规范也逐渐成为行业里约定俗成的规范
# 文件命名
文件名的规则在遵循目录命名的规则作为基础规则,但文件名的命名规则相比目录,略有不同
# 插件/组件/页面
单文件组件、插件/组件主体、页面的文件名应该始终是单词大写开头 (PascalCase)
单词大写开头对于代码编辑器的自动补全最为友好,因为这使得我们在 JS(X) 和模板中引用组件的方式尽可能的一致。然而,混用文件命名方式有的时候会导致大小写不敏感的文件系统的问题。
Vuejs 官方文档中,对于文件命名也有相应的 指导规范 (opens new window)
强烈建议
在此,强烈建议阅读官方推荐的 Vue官方推荐风格指南 (opens new window)
文件命名示例
✖
components
└─grid
├─grid.sass
├─headRow.vue
├─bodyrow.vue
├─grid.vue
└─index.js
✔
components
└─grid
├─grid.sass
├─HeadRow.vue
├─BodyRow.vue
├─Grid.vue
└─index.js
# CSS 样式预处理
对于 CSS 样式预处理方案,比较流行的有 SASS/SCSS
、LESS
和 Stylus
,大体上的使用方式类似,区别在于功能的多少与扩展的能力。
综合各方面考虑,开发规范如下(微信小程序不在讨论范围)
- 前端项目统一使用
SASS/SCSS
开发样式预处理内容 web-open-platform
项目使用Stylus
关于文件及目录的命名遵循 文件与目录命名 规则
# class 命名
对于 class name 的命名同样遵循全小写与单词间使用 "-" 隔开原则
命名示例
.user-container {
width: 100vw
.user-header {
background-color: #eee
}
}
# 样式抽象
一个工程通常会有大量的页面、组件和插件,功能虽不同,但风格必须统一。对于主题风格部分的内容,必须提取到专用样式文件中进行维护。类似的功能或结构的样式内容在多处独立维护,是冗余且低效的,多人协同开发时须杜绝该现象发生,在进行样式定义之前应互相询问是否存在重复定义的情况。
BTW
CSS 样式预处理,只使用最基本的结构嵌套功能是不够的,了解和使用高级特性才是提高效率和效果的最佳实践
# 路由命名规则
在路由(Vue Router)的命名中,依然遵循 文件与目录命名 规则;因为路由命名的结果最终会体现在浏览器的地址栏中,所以在路由的命名过程中依然是推荐结合业务结构的上下文级进行组合命名,内容必须做到精简、简洁,不要让最终呈现出来的地址链接过于冗长。
一个网站的路由结构通常两层就可以完全满足需求,所以除去页面布局结构外,大量的业务页面的路由均为同级,既然是同级,就需要通过路由的路径(path)来声明功能的业务结构
业务功能结构示例
├─系统管理
└─用户管理
└─角色授权管理
路由命名示例
✖
{ path: '/systemManage/userManage/roleAuth' }
✔
{ path: '/system/user/role-auth' }
现有项目命名情况改造实例
以现有素+管理平台的路由设置情况进行举例
✖ 不推荐
[
{ path: '/workbench/stockManager/stockType' }, // 存货类别
{ path: '/workbench/stockManager/goodsClassify' }, // 存货分类
{ path: '/workbench/stockManager/goodsSeries' }, // 存货系列
{ path: '/workbench/stockManager/goodsUnit' }, // 计量组单位
{ path: '/workbench/stockManager/stockBrands' }, // 存货品牌
{ path: '/workbench/stockManager/stockForm' }, // 存货形态
{ path: '/workbench/stockManager/stockArchives' } // 存货档案
]
✔ 推荐设置
[
{ path: '/workbench/stock/type' }, // 存货类别
{ path: '/workbench/stock/category' }, // 存货分类
{ path: '/workbench/stock/series' }, // 存货系列
{ path: '/workbench/stock/goods-unit' }, // 计量组单位
{ path: '/workbench/stock/brand' }, // 存货品牌
{ path: '/workbench/stock/form' }, // 存货形态
{ path: '/workbench/stock/file' } // 存货档案
]
通常情况下,对于路由的定义,不设置 name
属性,推荐仅对于使用频率较高的功能模块设置,例如登录、首页等最经常被使用的模块,另外就是业务中也经常会被多个场景中使用的情况
# 异步加载页面/组件
对于路由的定义推荐使用以下模式,以达到更好的按需加载的目的(打包拆分与按需加载)
[{
path: '/aaa/bbb',
component: () => import('@/views/abc')
}]
# 部分具体实践
工程思维,就在于拆文件的时候积累
- 文件绝不能超过 500 行,超过一定要思考怎么拆文件
- 函数对决不能超过 80 行,超过一定要思考怎么拆函数,思考函数分组,层次
- 代码嵌套层次不能超过 4 层,超过了就得改。多想想能不能 early return
- 从目录、package、文件、function 一层层下来,信息一定不能出现冗余。比如
file.FileProperty
这种定义。只有每个“定语”只出现在一个位置,才为“做好逻辑、定义分组/分层”提供了可能性 - 多用多级目录来组织代码所承载的信息,即使某一些中间目录只有一个子目录
- 随着代码的扩展,老的代码违反了一些设计原则,应该立即原地局部重构,维持住代码质量不滑坡。比如:拆文件、拆函数、重新调整目录结构
- 自己的项目代码,应该有一个内生的层级和逻辑关系。flat 平铺展开是非常不利于代码复用的,怎么复用、怎么组织复用
- 消灭重复!消灭重复!消灭重复!
# early return 示例
if (!needContinue) {
doA()
return
} else {
doB()
return
}
改造为 early return 的方式
if (!needContinue) {
doA()
return
}
doB()