个人单独开发或者多人协作开发除了使用 eslint 或者 tslint 控制代码规范外,还应当遵循以下的相关建议
本文档目前会涵盖前端涉及到的所有技术,不限于 html、css、js。待积累到一定程度,会拆分本文档到各个子模块
书写样式的几点考虑
- 命名规范--可阅读性高
- 不写重复的样式--DRY(don't repeat yourself)
- 可维护性高--不要有“这个css重写一遍比修改老文件快”的感受
- 可拓展性--为未来可能添加的样式留有可拓展的空间
- 保持统一性--多人合作的项目,应当保持统一的风格,这个统一应当包含统一的注释、统一的语法、统一的命名规范
CSS设计模式
- OOCSS,即:Object Oriented CSS。字面意思是面向对象的CSS。
提出的规范:
- Separate structure and skin (分离结构与主题) 减少对HTML结构的依赖
- Separate container and content (分离容器和内容) 增加CSS样式的复用性
减少对HTML结构的依赖:
针对列表中的a标签修改样式,不推荐使用 .container-list ul li a
这种方式来修改,原因是后期如果需要对html的结构进行重构,那么这里对应的样式也需要重新编写。这是由于html和css的耦合性高造成的。OOCSS针对这种情况推荐在a标签上加上list-item
样式,通过.container-list .list-item
的方式来降低耦合性。
增加CSS样式的复用性:
label
针对label样式的可重复部分先用一个样式.label
抽离出来,针对具体的不同样式(修饰类)使用.label-**
来增加额外的需求。这样抽取公共样式已达到复用的效果。(BootStrap就是根据OOCSS规范来的)
- []
CSS 文档分析
文档的拆分:
当我们针对某个具体的页面书写样式文件的时候,我们一般可能只需要新建一个css文件并在里面编写所有的css。我们这样写样式的原因一方面是因为单独的页面样式不会很复杂,不会有太多的代码。另一方面单独一个页面的样式在具体需要实现的功能上区分的不是那么明显,可能写完了就扔在那了,后面可能很少需要去更改。但是如果我们是针对一个庞大的项目呢?
下面是ant design
的部分样式文档结构:
--style
|
--color
|
--core
|
--motion
|
--base.less
|
--iconfont.less
|
--index.less
|
--motion.less
|
--mixins
|
--themes
|
--default.less
|
--index.css
--index.less
index.less:
@import "./themes/default";
@import "./core/index";
上面是ant design
的样式文档组织方式,将整个大的UI样式文档根据功能、作用拆分成一个个小的文件,然后在需要的地方通过@import
引入进来。这样组织的样式文档结构清晰明了,可阅读性很高,后期如果需要更改相应的样式,可以很快的定位到需要的文件。当然,选择哪种方式来组织需要根据实际情况来区分,需要因地制宜。
文档的说明:
一般来说我们会根据该样式文档的作用来给它起相应的文件名,但有的时候一个简单的样式文件名并不能全部显示需要了解的信息,我们可以在文档内容的开头写个目录(类似注释)来说明相关的信息。
建议的头部目录:
/*!
* version 1.0.0
*
* Copyright 2018-present,CompanyName.
* @Author ***
*
*/
写头部目录的目的:统一格式规范显得有逼格、便于后期开发人员的维护。
样式的命名:
参照上面CSS设计模式列出的几种规范,选择最适合自己的(若是多人合作,最好保持同一种样式书写规范)。
注释的拓展使用
- 修饰选择器
div ul li .item{
....
}
上面这种html和css耦合度很高的写法是不被推荐的,但我们之所以会这么写是潜意识中想明确出所写样式的作用范围。
我们可以采用下面这种写法来简单明确下样式的作用范围:
/*ul*/.breadcrumb{}
/*p*/.intro{}
- 继承标记
需要覆盖或继承框架、别人的样式代码时,在不是非常有把握的情况下,建议自己另写同名的样式去覆盖而不是在源文件上直接修改。这时候,我们最好在写的样式上标记下用途:
/**
* Extend '.foo{}' in default.css
*/
.foo{}
Html中的Class :
千万不要把Css样式用作JavaScript钩子。把JS行为和样式混在一起将无法对其分别处理,对后期的维护造成负担。
class可以作为一种选择器:
// jquery中class选择器
$('.class').css('width','100px');
// 原生js根据class获取dom对象
var obj =document.getElementByClassName('container');
上面这种将class混入js的写法我们大多数都做过,这样写代码会带来一个坏处:后期假如有人重构了html结构或者修改了部分的样式文件名,那么可能就会造成之前写的js不执行或者报错。
为了解决上述这种问题我们可以写一个JS专门的class:
简单的做法就是增加一个同样的class,然后添加一个前缀,比如js-
。这样含有js前缀的标记只是单纯的用来写js,不做其他的用途。
变量
变量的乱用
// 错误的写法
let kpi = 10; // 变量定义好后再也没有用过
function example() {
const a = 1;
const b = 2;
const c = a + b;
return c;
}
// 建议的写法
let kpi = 10; // 没用到的就删除掉,防止以后自己或者别人查看的时候感到困惑
function example() {
const a = 1;
const b = 2;
return a + b; // 数据只使用一次或者不使用就不需要装到变量中
}
变量的命名
// 自我感觉良好的缩写
let fName = 'jack'; // 看起来听规范的,缩写、驼峰式都用上了。但是 fName 是啥?
let lName = 'willen'; // 问题和上面一样
// 命名过于啰嗦
let nameString;
let theUsers;
// 建议的写法
let firstName = 'jack'; //见名能了其意
let lastName = 'willen';
// 尽量简洁明了
let name;
let users;
特定的变量
// 无说明的参数
if (value.length < 9) { // 为什么要小于 9,,9表示啥意思?
...
}
// 建议的写法
const MAX_INPUT_LENGTH = 8; // 用常量来存储
if (value.length < MAX_INPUT_LENGTH) {
...
}
变量的赋值
// 错误的写法
const MIN_NAME_LENGTH = 8;
let lastName = fullName[1]; // 假如fullName = ['abc']呢
if (lastName.length > MIN_NAME_LENGTH) {
...
}
// 建议的写法
const MIN_NAME_LENGTH = 8;
let lastName = fullName[1] || ''; // 防止 fullName[1] undefined
函数
函数命名
function isEmpty() {...} // 通过函数的名字,能大致看出该函数的作用以及可能返回的类型
功能函数
function sumFunc(a, b) {
let c = axios('...'); // c 的值是不固定的,导致整个求和函数的返回值不确定
return a + b + c;
}
// 功能函数使用纯函数,保证输入同样的参数能返回相同的结果
function sumFunc(a, b) {
return a + b;
}
动作函数
// 错误的函数命名
function event() {
...
}
// 建议的写法
function clickEvent() { // 动作函数以动词开头,能通过函数名表露出意图
...
}
函数功能
一个函数应当只完成一个独立的功能,不要一个函数混杂多个功能。
当函数需要做更多的事情时,它们将会更难进行编写、测试、理解和组合。当你能将一个函数抽离出只完成一个动作,它们将能够很容易阅读。如果你严格遵守本条规则,你将会领先于许多开发者。
过多的 if else 转变为 switch
// 不建议的 Coding style
if (a === 1) {
...
} else if (a === 2) {
...
} else if (a === 3) {
...
} else {
...
}
// 建议的 Coding style
switch(a) {
case 1:
...
case 2:
...
case 3:
...
default:
...
}
分割线内的列为考虑
禁止的写法:
禁止写行内样式
复用类
is-show
表示状态类(修饰类)、layout-sider
表示基础类(为了保持统一,哪怕这个类啥属性都没有也要写)