这是一篇自己推崇的前端基础代码规范,如果之后在实践的过程中有更适合自己的,会再更新。首先奉上一句话:
能愿动词说明
本文统一采用以下几个能愿动词作为规范的约束强度。
必须(Must)
:只能这样做,请无条件遵守绝不(Must Not)
:严令禁止,在任何情况下都不能这么做应该(Should)
:强烈建议这样做,但是并不强求不应该(Should Not)
:强烈建议不这样做,但是并不强求可以(May)
:你可以按照自己的喜好去做
命名风格
下面几个词组指代四种命名风格。
camelCase
:小驼峰PascalCase
:大驼峰kebab-case
:小写 + 中划线kebab_ase
:小写 + 下划线
代码风格
HTML部分
lang属性
html 标签 必须 设置 lang 属性,此属性值 应该 与目标用户的第一语言保持一致。
当使用i18n等工具进行页面语言的切换时,此属性值也 应该 一并切换。
1 | <html lang="zh_CN"> |
img 标签的 alt 属性
每一个 img 标签都 应该 有一个 alt 属性, 且它的内容 应该 尽可能详尽地描述这张图片的作用。
它除了能提供信息以及更好的 seo 之外,还能帮助视障人士。
中文和西文之间的空格
页面上的中文和西文(数字)之间 必须 有一个空格。
1 | <!-- bad --> |
CSS部分
CSS Reset
必须 在所有样式文件前引入 Normalize.css 用于消除各个浏览器之间的差异。
对于不同的项目,应该 根据需求设立 reset 样式集,并在 Normalize.css 之后引入。 Reset 样式集应该秉承最小化原则。
简化版的CSS BEM
CSS BEM是一种可以有效降低样式冲突概率的 css 选择器方法,但这种风格的代码对绝大部分项目来说是 too heavy 的。
这里提出一种简化的方案,只有”层级”和”断字”的概念。使用中划线 -
表示层级,使用下划线 _
表示断字。项目 必须 严格遵守该规范。
1 | <header class="header"> |
Sass
如果项目要使用 Css 预处理器, 应该优先使用 Sass,且 必须 使用 Scss 语法。使用 Scss 语法对上方的 html 代码进行选择会变得非常简单易行。
每一个 Scss 选择器后面 必须 有一个空行。
1 | .header { |
选择器命名
选择器命名的第一要务是见名知意。
- 对于一些常见的、约定俗成的单词简写,可以 使用简写形式。如:
description
->desc
- 绝不 使用简写后有多种释义,或是简写后无法辨别含义的单词简写。如:
description
->des
,fc
- 嵌套层级 不应该 过深,当出现三到四层嵌套后,可以使用全新的选择器名称。如:
.page-header-logo{ .title ...}
JS部分
Babel
所有项目都 应该 使用 Babel 进行转义,而源码都 应该 拥抱已经发布的 ECMAScript 特性。
ESLint
所有项目都 应该 使用 ESLint 进行代码格式检查。
const, let 和 var
const
必须 是第一公民,次之是 let
。被 Babel (或其他转义工具)转义的项目中 绝不 出现 var
。
命名
变量命名的第一要务是见名知意。
- 布尔型的变量 应该 以
is
或flag
开头。如:isVisible
- 数值类型的变量 必须 采用复数形式的名词。如:
users
,categories
- 对于单复同行的数值型变量,应该 添加其他的单词进行辅助释义。如:
newsList
- 对象类型的变量 必须 采用单数形式的名词。如:
user
- 函数 (方法) 命名 必须 是以动词开头的 camelCase 风格。如:
createUser
,validateForm
- 对于项目中约定的常量 (如配置项等),应该 使用 PASCAL_CASE 风格。如:
HEADER_MENU
,PRIMARY_COLOR
- 类( Class )的名称 必须 采用 PascalCase 形式,且 应该 拟人化。如:
Permission
,FormValidator
- 任何变量的命名都 不应该 过于生僻和抽象
一些推荐使用的函数首部动词
do
/deal
:做某些事情go
:跳转、前往get
/fetch
:获取某些事物set
:设置某些事物make
/create
:创建edit
/update
:编辑delete
/destory
:删除handle
:被其他操作触发了
Restful Actions
对于项目中的接口,应该 将 ajax 请求拆分为请求函数以实现复用以及提高项目的可维护性。
如果接口使用 Restful API,那么前端对应的方法名 可以 按照下面的规范来进行命名。
get
/books
=>reqFetchBooks
get
/books/:id
=>reqShowBooks
post
/books
=>reqCreateBooks
post,put,patch
/books/:id
=>reqUpdateBooks
delete
/books/:id
=>reqDestoryBooks
数组的循环
在使用循环时, 不应该 使用item
作为数组的元素名,而 应该 使用数组的单数形式。
1 | // bad |
if的处理
每一个if
都 必须 囊括所有情况,也就是说每一种逻辑都可以被 if 处理。
1 | // bad |
部分if else
逻辑 可以 通过及时 return
减少嵌套层数。
1 | // good |
过多的!a || b
应该 被转换为!(a && b)
,这种逻辑更符合直觉。
1 | // not bad |
注释
- 注释本身 不应该 对变量或方法本身是做什么的进行解释。这要求变量命名尽可能得见名知意。
Vue部分
NOTICE HERE: Vue 的相关规范全部基于官方的风格指南, 并在此基础上进行了一些修改和约束。
组件文件命名
- 页面、路由相关的组件 应该 使用一个单词命名
- 非页面、路由相关的组件 应该 使用
PascalCase
风格命名 - 组件 应该 拟人化。如:
UserCreator
,Selector
文件引入
如果文件夹内拥有index.vue
,那么引入时 应该 省略 index 字样, 并在末尾添加 /
。
1 | // ok |
引入组件时,模块名 必须 为 PascalCase
。
1 | // bad |
根标签书写规范
vue 文件中的标签书写顺序 必须 为:
<template></template>
<script></script>
<style></style>
<template></template>
根标签
每一个根标签下的顶级元素都 必须 有一个与当前文件名对应的 css 选择器。在本规范中, 应该 使用文件名
的kebab_case
结构作为该 css 选择器。如:SelectorGender
->selector_gender
如果为了进一步降低组件间的样式冲突的可能性, 可以 使用 文件夹层级
+ 文件名
共同组装成根组件的根选择器。假定有以下目录结构:
1 | |-- common <dir> |
那么其对应的唯一 css 选择器名应该为:
1 | <template> |
<script></script>
根标签
实例选项顺序
组件实例中的选项顺序 必须 按照 vue 风格指南的要求进行排版
el
name
parent
functional
delemiters
comments
components
directives
filters
extends
mixins
inheritAttrs
model
props/prosData
data
computed
watch
beforeCreated
created
beforeMounted
mounted
beforeUpdate
updated
activated
deactivated
beforeDestory
destoryed
methods
template/render
renderError
留白
各个选项间 必须 间隔一个空行,而内部的值或方法不空行。
1 | export default { |
实例选项:name
每一个组件 必须 有一个 name
实例选项,其值 必须 为被其他组件引入时的模块名。如果你的组件命名完全符合本规范,那么一般情况下,此属性的值应与组件的文件名保持一致。
1 | /** |
实例选项:props
组件需要的参数,都 应该 拥有完善的验证规则。
1 | export default { |
实例选项:data
- 不应该 使用
Vue.set()
方式为组件扩展响应式的 data - 应该 将一些同属于某一块页面元素的 data 合并为对象的形式,避免 data 的扁平化
- 每一个 data 都 必须 是被使用到的
实例选项: 生命周期函数
生命周期函数内 不应该 直接书写过多的业务逻辑。如果逻辑过多,应该 在 methods 中定义独立的函数并在生命周期函数中进行调用。
<style></style>
根标签
- 必须 添加 scoped 属性
- 必须 使用 sass 预处理器,并且使用 scss 语法
- 所有的组件内样式 必须 被该组件的唯一 css 选择器包裹
1
2
3
4
5
6
7
8
9
10
11<template>
<div class="selector_gender">
<!-- ... -->
</div>
</template>
<style scoped lang="scss">
.selector_gender {
/* ... */
}
</style>
关于命名的(最佳)实践
- 在 Dom 上绑定的事件回调方法 应该 使用
on
+动词
+名词
形式。如:@click="onCreateUser"
- 子组件 emit 的事件名称 应该 使用
动词的一般现在时
。如:@click
,@submit
- 子组件 emit 的事件回调方法 应该 使用
handle
+名词
+动词过去式
形式。如:@submit="handleUserCreated"
- 应该 正确使用
or
和and
。详见下方示例
一个完整的例子:每个方法和变量都见名知意,并且永不重复!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63<template>
<div class="users">
<el-button @click="onCreateUser">Create User</el-button>
<el-table>
<el-table-column>...</el-table-column>
<el-table-column>
<template #default="scope">
<el-button @click="onEditUser(scope.row)">Edit User</el-button>
<el-button :loading="isDeletingUser" @click="onDeleteUser(scope.row)">Delete User</el-button>
</template>
</el-table-column>
</el-table>
<user-creator-and-editor
ref="userCreatorAndEditor"
@submit="handleUserCreatedOrEdited">
</user-creator-and-editor>
</div>
</template>
<script>
import UserCreatorAndEditor from './UserCreatorAndEditor'
import { reqDestoryUser } from '@/api/user'
export default {
name: 'Users',
components: { UserCreatorAndEditor },
data() {
return {
isDeletingUser: false,
}
},
methods: {
onCreateUser() {
this.$refs.userCreatorAndEditor.open({ type: 'create' });
},
onEditUser() {
this.$refs.userCreatorAndEditor.open({ type: 'edit', userId: id });
},
handleUserCreatedOrEdited(result) {
if(result) {
// ...
} else {
// ...
}
},
async onDeleteUser({ id }) {
try {
this.isDeletingUser = true;
await reqDestoryUser(id);
// ...
} catch (e) {
// ...
} finally {
this.isDeletingUser = false
}
}
}
}
</script>
Vue Router
不应该 使用路由大量传递参数,请尽可能地保证clean and beautiful
。
Vuex
应该 使用module
组织 vuex,而非全部注册在顶级。
其他
- 绝不 给 Vue 挂载大体量的插件或扩展, 应该 在需要用到的页面进行按需引入
- 不应该 直接选取某个 dom 元素进行直接的 dom 操作( Echarts 等插件除外)
文档
项目的技术文档 必须 使用 Markdown 格式编写。
标点符号
- 英文文档 必须 使用半角标点符号
- 中文文档中以下标点符号 必须 使用半角,并在其后添加一个空格
- 引号:
""
- 冒号:
:
- 感叹号:
!
- 问号:
?
- 所有的括号:
() [] {}
- 引号:
- 中文文档中以下标点符号 必须 使用全角,其后不需要添加空格
- 逗号:
,
- 句号:
。
- 省略号:
……
- 逗号:
Markdown 语法约束
- 必须 有且仅有一个一级标题
- 标题的层级最多 不应该 超过三级
- 句子的末尾 必须 有句号
- 无序列表和有序列表的末尾 不应该 添加句号
- 应该 优先选用无需列表而非有序列表
- 用于表明格式的关键字符 必须 前后各留一个空格
- 标题与段落之间 必须 前后各留一个空行
的,得,地
必须 正确使用的
,得
,地
。
项目版本
版本号
项目开发过程中的版本迭代 应该 遵循类似 npm 的版本定义方法。即:
1.1.1
->1.1.2
: 向下兼容的问题修复1.1.1
->1.2.1
: 向下兼容的功能迭代1.1.1
->2.1.1
: 发生了非向下兼容的功能迭代
版本迭代及分支管理
master
分支 必须 对应线上代码- 对于开发告一段落,但仍需维护的版本, 必须 检出一条以
stable/
开头的分支进行维护。如:stable/v1
项目依赖
- 安装依赖时 必须 按照功能严格区分生产环境依赖和开发环境依赖
- 绝不 遗留未被使用的依赖。如果不使用某个依赖时, 必须 第一时间进行卸载
- 绝不 在未获得其他开发人员同意的情况下升级依赖版本
- 应该 优先使用使用量大、受众面广的依赖
Git
使用If
Windows 下的 Git 默认使用crlf
作为换行符,甚至会将lf
转换为crlf
。本规范要求所有的换行都 必须 使用lf
风格。
Q: 安装 Git 时,忘记去勾了 crlf 自动替换的选项,怎么办?
A: 执行以下命令:
1 | git config --global core.eol lf |
分支命名
- 开发分支 必须 是
develop
- 功能分支 必须 以
feature/
开头。如:feature/user_system
- 开发完毕,但仍需维护的版本, 必须 检出一条以
stable/
开头的分支进行维护。如:stable/v1
Merge Request(Pull Request)
每一次分支合并都 必须 发起一个Merge Request
,并且交由他人评审。
Vue Cli
文件组织
src
api
: 存放 API 资源assets
: 存放需要被 Webpack 处理的静态资源components
: 存放于项目无关的公共组件。理论上这些组件可以被任何项目直接使用config
: 存放一些项目配置文件models
: 存放前端的数据模型。如果项目使用了 Typescript, 理论上不需要设置改目录router
: Vue 路由store
: Vuex。 应该 只包含modules
和index.js
,保证 vuex 所有功能都尽可能按照模块划分modules
: Vuex 的模块index.js
styles
: 存放全局样式。样式文件 必须 使用 Scss 进行组织; 作为子文件的样式文件 必须 使用_
开头_common.scss
: 公共样式文件_hack.scss
: 对各种组件库或其他样式进行加强修改。理论上这个样式文件的内容 应该 尽可能地少_mixins.scss
: 提供全局的 Scss Mixins_reset.scss
: 对页面样式进行重置。理论上这个样式文件的内容 应该 尽可能地少main.scss
: 按照一定的顺序注册全部样式文件。被main.js
引入resource.scss
: 被scss-loader
处理,注册全局可用的 Scss 资源
utils
: 各种工具http.js
: 请求层。必须 优先使用axios
views
: 视图层App.vue
main.js
: 文件内容 必须 尽可能短小且清晰
.editorconfig
.prettierignore
.prettierrc.js
.prettierrc.js
CHANGELOG.md
: 项目更新日志。在每一次上线前都 必须 进行补全README.md
: 用来说明项目,以及帮助其他人快速上手项目
main.scss 组织
由于样式存在后者覆盖前者的问题,因此 main.scss 必须 按照一定的顺序进行组织。
1 | // 网络资源 (network resources) |
Scss全局资源
参考官方文档: https://cli.vuejs.org/zh/guide/css.html#向预处理器-loader-传递选项
在src/styles/
目录下创建resources.scss
文件,用于存放全局可以使用的样式资源,如变量,mixin 等。
1 | @import "variables"; |
在vue.config.js
中进行了配置
1 | modules.exports = { |
Editorconfig
每一个项目都 必须 添加Editorconfig
文件,并且每一个开发人员的编辑器都 必须 安装该插件。
下面是一份推荐使用的 editorconfig 配置:
1 | root = true |
Prettier
所有项目都 必须 使用Prettier
进行代码的格式化。
下面是一份推荐使用的 prettier 配置:
1 | // .prettierrc.js |
- 本文作者: Jambo
- 版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!