总体原则
- 驼峰命名(camelCase):用于定义 JavaScript
基本数据类型
、函数方法
。 - 帕斯卡命名(PascalCase):用于 JavaScript 声明
Class类
、Object对象
、Array数组
引用数据类型。 - 短横线命名(kebab-case):用于自定义
HTML视图
、SCSS样式
、Assets资源
,即样式与视图相关的自定义元素都采用该方式命名。
<div>
<main id="app">
<section class="article-content">
<my-paragraph>kebab-case</my-paragraph>
</section>
</main>
<template>
<style>
#app {
background: url(../assets/banner-logo.png); // kebab-case
}
.article-content {
font-size: 18px; // kebab-case
}
</style>
<script>
let currentDate = "Tue Oct 10 2017 17:52:04 GMT+0800 (CST)"; // camelCase
const changeDate = function () {
console.log(new Date()); // camelCase
};
const YourName = {
name: "Hank", // PascalCase
};
</script>
</template>
</div>
所有代码缩进必须使用 2 个空格,并优先使用单引号',除非字符串嵌套需要,否则禁止单-双引号混用。
JavaScript & ES6
适用于使用 Babel 提供 ES6 预编译环境的场景。
命名原则
代码块的花括号{
、流程控制语句的小括号(
前必须放置1 个空格,且每个函数、代码块之前通过换行进行分隔。
class Hank {
constrocter() {
(this.height = "182cm"), (this.weight = "75kg");
}
// 换行分隔代码块
toString() {
// 花括号前放置空格
if (this.height && this.weight) {
// 小括号前放置空格
console.info("toString");
}
}
}
不要在函数参数列表的前后添加任何空格,但是可以使用1 个空格将 JavaScript 运算符分隔开,并且在每个代码文件末尾保留1 个空行。
// 函数参数列表前后不添加空格
((window) => {
var self = window; // 使用1个空格分隔运算符
})(window);
// 保留1个空行
使用美元符$
作为存储jQuery 对象变量名称的前缀。
const menu = $("#menu"); // bad way
const $menu = $("#menu"); // good way
使用下划线_
作为代码中私有变量的前缀,避免其它小伙伴的操作对该变量造成污染。
function traverse(array) {
let _index = 0; // 将数组索引声明为私有变量,防止误操作导致索引泄露
for (_index; array.length < _index; _index++) {
console.log(array[_index]);
}
}
严禁在项目中使用单个字母和拼音命名的变量和函数名称。
数据类型
- 基本数据类型:
String、Number、Boolean、null、undefined
,使用let进行定义,不再使用 var。 - 引用数据类型:
Object、Array、Function
,引用数据类型全部通过const进行定义。
let myBoolean = true;
let myNumber = 32;
let myString = "this is a string";
const array = [0, 1, 2, 3, 4, 5];
const object = { a: "a", b: "b", c: "c" };
let 和 const 都具有代码块级的作用域,书写时注意将两者进行分组。
对象
使用字面量语法创建对象,而不要使用new
关键字。
const myObject = new Object(); // not recommend
const myObject = {}; // it is correct
对象当中的方法使用简写函数、简写属性进行定义。
let username = "admin";
let password = "admin";
vm.login = {
username,
password, // 简写属性
// 简写函数
auth(username, password) {
// ... ...
},
};
当对象中同时存在简写属性和普通属性时,需要将简写属性写到单独的组。
vm.group = {
// 简写属性
username,
password,
isAuthorized,
// 普通属性
age: "20",
height: 182,
weight: 76,
homeland: "CHINA",
};
使用.
运算符访问对象属性,或者使用[]
通过变量访问属性。
const user = {
height: 182,
weight: 75,
};
console.info(user.height);
console.info(user["weight"]);
ES6 中新出现的class
关键字,实质是构造函数创建对象的一种糖衣语法,目的是更加容易的向对象添加原型方法。因此,建议尽可能使用class
创建类及原型方法,避免在构造函数上使用prototype
关键字。
//定义类
class Point {
// 构造函数
constructor(x, y) {
this.x = x; // this指向实例对象
this.y = y;
}
// 定义类方法不需要使用function关键字进行声明
toString() {
return this.x + this.y;
}
}
通过在class
类方法上返回this
对象,可以在该类的实例化对象上进行链式方法调用。
class Hank {
constructor(name, age) {
this.age = age;
this.name = name;
}
printName() {
console.info(this.name);
return this;
}
printAge() {
console.info(this.age);
return this;
}
}
const hank = new Hank("uinika", 18);
hank.printName().printAge();
代码中尽可能使用extends
实现继承,因为extends
是 ES6 内建的**原型继承方法,不会对instanceof()
的返回结果形成破坏。
class Uinika extends Hank {
constructor(height, weight) {
super("uinika", 18); // 实例化父级构造器
this.height = height;
this.weight = weight;
}
print() {
console.log(this); // 打印自己以及父级构造器当中的属性
}
}
数组
- 使用字面量语法创建数组,而不要使用
new Array()
关键字。
const myArray = new Array(); // not recommend
const myArray = []; // it is correct
- 添加数组元素时使用
Arrary.push()
,而不要使用索引赋值。
const myArray = [];
myArray[myArray.length] = "uinika"; // not recommend
myArray.push("uinika"); // it is correct
- 使用 ES6 的扩展运算符(spread)
...
复制数组。
const target = ["A", "B", "C", "D"];
const copy = [];
// not recommend
for (let index = 0; index < target.length; index++) {
copy[i] = target[i];
}
// it's correct
const copy = [...target];
- 使用 ES6 提供的
Array.from()
方法将类数组对象(同时具备索引和长度)转换为数组。
const myObject = {
"0": "A",
"1": "B",
"2": "C",
length: 3,
};
let myArray = Array.from(myObject); // ['A', 'B', 'C']
字符串
为避免频繁按下shift+'
组合键,请在代码中尽可能使用单引号'
声明字符串。
const name = "Hank"; // bad way
const name = "Hank"; // good way
字符串过长时,必须通过+
或者\
运算符进行换行和缩进处理,让代码更加美观易读。
// bad way
let bad = "hank is first name and zheng is last name";
// good way
let good =
"hank is first name \
and zheng is last name";
// best way
let best = "hank is first name" + "and zheng is last name";
拼接字符串HTML 模板时,请使用模板字符串${}
,而非字符串连接符+
。
// bad
function sayHi(name) {
return "How are you, " + name + "?";
}
// good
function sayHi(name) {
return `How are you, ${name}?`;
}
函数
使用函数声明(function declaration)代替函数表达式(function expression),因为前者可以进行函数提升(function hoisting)。
// bad
const bad = function () {};
// good
function good() {}
需要使用函数表达式、匿名函数的场景下,请直接使用箭头函数符号=>
,这样可以在箭头函数内部创建新的this
作用域。
// 一个标准的箭头函数写法
(name, password) => {
console.info(name, password);
};
// 箭头函数的简写形式
(name) => name + "zheng";
使用箭头函数来书写立即调用的函数表达式(IIFE,Immediately Invoked Function Expression)。
(() => {
console.info("Hello Hank!");
})();
布尔运算
尽可能使用===
和!==
去同时比较值与数据类型,而非通过==
和!=
仅比较值。
if (variable1 === "" && variable2 !== 0) {
console.info("just a test!");
}
各数据类型的布尔运算结果如下,使用if()
等逻辑判断语句时需要注意。
- 对象类型的
object
和array
都计算为true
,无论其是否为空对象{}
或者空数组[]
。 - 空字符串类型
''
计算为false
,但非空字符串'string'
计算为true
。 - 数字类型
NaN
和0
计算为false
。 undefined
和null
都是false
。
if ([0]) {
// 结果为true,因为JavaScript中object和array都同属对象类型,布尔运算时对象类型都会被渲染为true。
}
利用 JavaScript 逻辑判断语句的强制数据类型转换特性,可以更加简洁的书写布尔判断。
if (name !== "") {
} // bad
if (name) {
} // good
if (collection.length > 0) {
} // bad
if (collection.length) {
} // good
如果通过if...else...
语句使用多行代码块,则else
放在if
代码块关闭括号}
同一行。
// bad job
if (test) {
...
}
else {
...
}
// good job
if (test) {
...
} else {
...
}
注释
- 使用
/** */
作为多行注释,用来标注全局功能模块的名称、类型、参数、返回值、描述等信息。
/**
* @name auto-resize
* @type directive
* @param 数值类型,表示缩进的像素值
* @return null
* @description 自动根据当前window大小计算页面的显示尺寸
*/
- 使用
/* */
作为单行注释,标注局部代码块的参数、返回值、描述信息。
/*
* @param 用户输入字符串
* @return null
* @description 去除目标字符串全部空格
*/
function trim(input) {
if (typeof input === "string" && input) input.replace(/\s/g, "");
}
- 使用
//
作为行内注释,标记代码段信息。
function trustHtml($sce) {
return $sce.trustAsHtml(val); //返回被信任的HTML字符串
}
使用
// TODO:
格式注释描述问题本身,使用// FIXME:
格式注释描述问题解决方式。
() => {
issue(); // TODO: 描述问题本身的信息
handle(); // FIXME: 描述如何解决问题
return this;
};
解构赋值
通过解构赋值存取多属性对象,可以减少临时变量声明的数量。
/* 对象的解构赋值 */
function getFullName1(user) {
const name = user.name; // bad way
const password = user.password;
return `${name} ${name}`;
}
function getFullName2(user) {
const { name, password } = user; // good way
return `${name} ${password}`;
}
function getFullName3({ name, password }) {
return `${name} ${password}`; // best way
}
/* 对象的解构赋值 */
const array = [1, 2, 3, 4];
const array1 = array[0]; // bad way
const array2 = array[1]; // bad way
const [array1, array2] = array; // good way
函数返回值时,直接返回对象
{}
而非数组[]
,避免因为数组索引改变导致不能正确读取相应位置数据。
CSS & SCSS
命名原则
reset.scss
:消除默认样式和浏览器差异,并设置部分标签的初始样式,例如<html>
和<body>
的宽高度的100%
。
@import "./base";
@import "./color";
.reset {
margin: 0;
padding: 0;
border: none;
outline: none;
width: 100%;
height: 100%;
}
html {
@extend .reset;
body {
@extend .reset;
font-size: 16px;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB",
"Microsoft YaHei", "微软雅黑", Arial, sans-serif;
#app {
@extend .reset;
.router {
@extend .reset;
}
}
}
}
color.scss
:项目中页面的所有取色必须来自这个颜色变量列表,色表内部的变量以color-颜色-深度
格式命名。
// infomation
$color-primary: $color-blue;
$color-success: #13ce66;
$color-warning: #f7ba2a;
$color-danger: #ff4949;
// scheme
$color-blue: #20a0ff;
$color-blue-light: #58b7ff;
$color-blue-dark: #1d8ce0;
$color-pink: #ff0097;
$color-cyan: #4eb3b9;
$color-black: #1f2d3d;
$color-black-light: #324057;
$color-black-light-extra: #475669;
$color-silver: #8492a6;
$color-silver-light: #99a9bf;
$color-silver-light-extra: #c0ccda;
$color-gray: #d3dce6;
$color-gray-light: #e5e9f2;
$color-gray-light-extra: #eff2f7;
$color-white: #ffffff;
$color-white-dark: #f9fafc;
base.scss
:基础的公用快捷样式,通过 HTML 元素的 class 属性直接使用。skin.scss
: 全局 UI 插件的样式补丁,如果存在多种皮肤,则以skin-xx.scss
方式进行命名。grid.scss
:自定义的 CSS 栅格系统,直接通过 HTML 元素及 class 属性使用。
每个 Vue 或者 React 根级组件的样式都独立到单独模块书写,禁止在顶层 ID 选择器之外再定义其它 CSS 样式,避免对全局样式形成污染。私有组件顶层 CSS 选择器使用id
属性定义,公用组件的顶层选择器使用class
属性定义,。
@import "../common/styles/base.scss";
#ID {
// 一律使用单行注释
}
为了避免 SASS 中使用多行注释时,将注释内容打包至最终产品代码,因此非公用模块的注释一律使用单行注释
//
。
布局选择器
语义 | 命名 | 简写 |
---|---|---|
文档 | doc | doc |
头部 | head | hd |
主体 | body | bd |
尾部 | foot | ft |
主栏 | main | mn |
主栏子容器 | main-container | mcc |
侧栏 | side | sd |
侧栏子容器 | side-container | sdc |
盒容器 | wrap/box | wrap/box |
模块/组件选择器
语义 | 命名 | 简写 |
---|---|---|
导航 | nav | nav |
子导航 | subnav | snav |
面包屑 | crumb | crm |
菜单 | menu | menu |
选项卡 | tab | tab |
标题区 | head/title | hd/tt |
内容区 | body/content | bd/ct |
列表 | list | lst |
表格 | table | tb |
表单 | form | fm |
热点 | hot | hot |
排行 | top | top |
登录 | login | log |
标志 | logo | logo |
广告 | advertise | ad |
搜索 | search | sch |
幻灯 | slide | sld |
提示 | tips | tips |
帮助 | help | help |
新闻 | news | news |
下载 | download | dld |
注册 | regist | reg |
投票 | vote | vote |
版权 | copyright | cprt |
结果 | result | rst |
标题 | title | tt |
按钮 | button | btn |
输入 | input | ipt |
功能选择器
语义 | 命名 | 简写 |
---|---|---|
浮动清除 | clear-both | cb |
向左浮动 | float-left | fl |
向右浮动 | float-right | fr |
内联块级 | inline-block | ib |
文本居中 | text-align-center | tac |
文本居右 | text-align-right | tar |
文本居左 | text-align-left | tal |
垂直居中 | vertical-align-middle | vam |
溢出隐藏 | overflow-hidden | oh |
完全消失 | display-none | dn |
字体大小 | font-size | fs |
字体粗细 | font-weight | fw |
颜色/背景选择器
语义 | 命名 | 简写 |
---|---|---|
字体颜色 | font-color | fc |
背景 | background | bg |
背景颜色 | background-color | bgc |
背景图片 | background-image | bgi |
背景定位 | background-position | bgp |
边框颜色 | border-color | bdc |
状态选择器
语义 | 命名 | 简写 |
---|---|---|
选中 | selected | sel |
当前 | current | crt |
显示 | show | show |
隐藏 | hide | hide |
打开 | open | open |
关闭 | close | close |
出错 | error | err |
不可用 | disabled | dis |
前端基础架构已经提供了基于 postcss 的后置处理器 autoprefixer(对前置 SASS 编译后的 CSS 进行再处理),因此编写样式时不再手动处理
-webkit-
、-moz-
等兼容性前缀。
HTML
HTML 标签的语义化有助于形成构架良好的 DOM 结构,有助于搜索引擎优化和提升可访问性, 尽可能保持 HTML DOM 结构的优雅。
整体 DOM 结构
统一使用 HTML5 提供的<!DOCTYPE html>
文档类型声明,并在<head>
中使用<link>
引入外部 CSS 文件,然后在<body>
底部通过<script>
引入 JavaScript 文件。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>Aves</title>
<meta name="renderer" content="webkit" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<div id="app">
<main id="dashboard"></main>
</div>
</body>
</html>
组件 DOM 结构
每个 Vue 或者 React 根级组件的顶层元素(通常是指全局的路由视图)一律通过<main>
元素定义,因为同一个文档中<main>
标签只可以出现一次,自定义组件一律使用<div>
进行定义,id
属性命名则使用短横线连接的router-component
格式。
<!-- 全局路由视图 -->
<main id="router">
<!-- 组件 -->
<div id="router-component"></div>
</main>