总体原则
- 驼峰命名(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>
