init
This commit is contained in:
commit
25d7fc15cb
|
@ -0,0 +1,46 @@
|
||||||
|
severity: error
|
||||||
|
|
||||||
|
linters:
|
||||||
|
|
||||||
|
BorderZero:
|
||||||
|
enabled: true
|
||||||
|
convention: zero
|
||||||
|
|
||||||
|
BemDepth:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
DeclarationOrder:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
ExtendDirective:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
LeadingZero:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
NameFormat:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
PrivateNamingConvention:
|
||||||
|
enabled: true
|
||||||
|
prefix: _
|
||||||
|
|
||||||
|
PropertySortOrder:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
QualifyingElement:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
SelectorFormat:
|
||||||
|
enabled: true
|
||||||
|
convention: hyphenated_BEM
|
||||||
|
class_convention: ^(?!js-).*
|
||||||
|
class_convention_explanation: should not be written in the form js-*
|
||||||
|
|
||||||
|
SingleLinePerProperty:
|
||||||
|
enabled: true
|
||||||
|
allow_single_line_rule_sets: false
|
||||||
|
|
||||||
|
StringQuotes:
|
||||||
|
enabled: true
|
||||||
|
style: double_quotes
|
|
@ -0,0 +1,345 @@
|
||||||
|
# CSS / Sass 规范指南
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
1. [术语](#terminology)
|
||||||
|
- [规则声明](#rule-declaration)
|
||||||
|
- [选择器](#selectors)
|
||||||
|
- [属性](#properties)
|
||||||
|
1. [CSS](#css)
|
||||||
|
- [文件引用](#file-import)
|
||||||
|
- [格式](#formatting)
|
||||||
|
- [属性顺序](#order)
|
||||||
|
- [注意事项](#careful)
|
||||||
|
- [注释](#comments)
|
||||||
|
- [OOCSS 和 BEM](#oocss-and-bem)
|
||||||
|
- [ID 选择器](#id-selectors)
|
||||||
|
- [JavaScript 钩子](#javascript-hooks)
|
||||||
|
1. [Sass](#sass)
|
||||||
|
- [语法](#syntax)
|
||||||
|
- [排序](#ordering-of-property-declarations)
|
||||||
|
- [变量](#variables)
|
||||||
|
- [Mixins](#mixins)
|
||||||
|
- [扩展指令](#extend-directive)
|
||||||
|
- [嵌套选择器](#nested-selectors)
|
||||||
|
|
||||||
|
<a name="terminology"></a>
|
||||||
|
## 术语
|
||||||
|
|
||||||
|
<a name="rule-declaration"></a>
|
||||||
|
### 规则声明
|
||||||
|
|
||||||
|
我们把一个(或一组)选择器和一组属性称之为 “规则声明”。举个例子:
|
||||||
|
|
||||||
|
```css
|
||||||
|
.listing {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="selectors"></a>
|
||||||
|
### 选择器
|
||||||
|
|
||||||
|
在规则声明中,“选择器” 负责选取 DOM 树中的元素,这些元素将被定义的属性所修饰。选择器可以匹配 HTML 元素,也可以匹配一个元素的类名、ID, 或者元素拥有的属性。以下是选择器的例子:
|
||||||
|
|
||||||
|
```css
|
||||||
|
.my-element-class {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
|
||||||
|
[aria-hidden] {
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="properties"></a>
|
||||||
|
### 属性
|
||||||
|
|
||||||
|
最后,属性决定了规则声明里被选择的元素将得到何种样式。属性以键值对形式存在,一个规则声明可以包含一或多个属性定义。以下是属性定义的例子:
|
||||||
|
|
||||||
|
```css
|
||||||
|
/* some selector */ {
|
||||||
|
background: #f1f1f1;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="css"></a>
|
||||||
|
## CSS
|
||||||
|
|
||||||
|
<a name="file-import"></a>
|
||||||
|
### 文件引用
|
||||||
|
|
||||||
|
* [建议] 使用 `link` 的方式调用外部样式
|
||||||
|
* [强制] 不允许在 `<style>` 块中使用 `@import`。
|
||||||
|
* [强制] 不允许使用 `style` 属性写行内样式。
|
||||||
|
|
||||||
|
<a name="formatting"></a>
|
||||||
|
### 格式
|
||||||
|
|
||||||
|
* [强制] 使用 2 个空格作为缩进。
|
||||||
|
* [强制] 全小写,使用`-`作为相关类的自然间断(不要使用`_`和 camelCase)。
|
||||||
|
* [建议] 不要使用 ID 选择器。
|
||||||
|
* [强制] 在一个规则声明中应用了多个选择器时,每个选择器独占一行。
|
||||||
|
* [强制] 在规则声明的左大括号 `{` 前加上一个空格。
|
||||||
|
* [强制] 在属性的冒号 `:` 后面加上一个空格,前面不允许空格。
|
||||||
|
* [强制] 逗号分隔的取值,都应该在逗号之后增加一个空格
|
||||||
|
* [强制] 规则声明的右大括号 `}` 独占一行。
|
||||||
|
* [建议] 规则声明之间用空行分隔开。
|
||||||
|
* [建议] 每个选择器最后一条属性 `;` 不能省略
|
||||||
|
* [建议] 所有的十六进制值都应该使用小写字母,例如 `#fff`
|
||||||
|
* [强制] 为选择器中得属性取值添加**双引号**,例如 `input[type="text"]`
|
||||||
|
* [建议] 不要为 0 指明单位,比如使用 `margin: 0;` 而不是 `margin: 0px;`
|
||||||
|
* [建议] 在定义无边框样式时,使用 `0` 代替 `none`。
|
||||||
|
|
||||||
|
|
||||||
|
**Bad**
|
||||||
|
|
||||||
|
```css
|
||||||
|
.avatar{
|
||||||
|
border-radius:50%;
|
||||||
|
border:2px solid white; }
|
||||||
|
.no, .nope, .not_good {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
#lol-no {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Good**
|
||||||
|
|
||||||
|
```css
|
||||||
|
.avatar {
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2px solid white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.one,
|
||||||
|
.selector,
|
||||||
|
.per-line {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="order"></a>
|
||||||
|
### 属性顺序
|
||||||
|
1. Positioning
|
||||||
|
1. Box model 盒模型
|
||||||
|
1. Typographic 排版
|
||||||
|
1. Visual 外观
|
||||||
|
|
||||||
|
Positioning 处在第一位,因为他可以使一个元素脱离正常文本流,并且覆盖盒模型相关的样式。盒模型紧跟其后,因为他决定了一个组件的大小和位置。
|
||||||
|
|
||||||
|
```css
|
||||||
|
.declaration-order {
|
||||||
|
/* Positioning */
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
|
/* Box-model */
|
||||||
|
display: block;
|
||||||
|
float: right;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
|
||||||
|
/* Typography */
|
||||||
|
font: normal 13px "Helvetica Neue", sans-serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #333;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
/* Visual */
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border: 1px solid #e5e5e5;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
/* Misc */
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="careful"></a>
|
||||||
|
### 注意事项
|
||||||
|
|
||||||
|
* [强制] 避免过度使用简写。.btn 可以很好地描述 `button`,但是 `.s` 不能代表任何元素。
|
||||||
|
* [建议] `class` 的命名应该尽量短,也要尽量明确。
|
||||||
|
* [强制] 使用有意义的名称;使用结构化或者作用目标相关,而不是抽象的名称。
|
||||||
|
* [建议] 命名时使用最近的父节点或者父 class 作为前缀。
|
||||||
|
* [强制] 使用 classes 而不是通用元素作为选择器,不允许 `div.doc`。
|
||||||
|
* [建议] 避免在经常出现的组件中使用一些属性选择器 (例如,[class^="..."])。浏览器性能会受到这些情况的影响。
|
||||||
|
* [建议] 减少选择器的长度,每个组合选择器选择器的条目应该尽量控制在 3 个以内。
|
||||||
|
|
||||||
|
<a name="comments"></a>
|
||||||
|
### 注释
|
||||||
|
|
||||||
|
* 建议使用行注释 (在 Sass 中是 `//`) 代替块注释。
|
||||||
|
* 建议注释独占一行。避免行末注释。
|
||||||
|
* 保持注释内容与星号之间有一个空格的距离 `/* 普通注释 */`
|
||||||
|
* 给没有自注释的代码写上详细说明,比如:
|
||||||
|
- 为什么用到了 z-index
|
||||||
|
- 兼容性处理或者针对特定浏览器的 hack
|
||||||
|
|
||||||
|
<a name="oocss-and-bem"></a>
|
||||||
|
### OOCSS 和 BEM
|
||||||
|
|
||||||
|
出于以下原因,建议使用 OOCSS 和 BEM 的某种组合:
|
||||||
|
|
||||||
|
* 可以帮助我们理清 CSS 和 HTML 之间清晰且严谨的关系。
|
||||||
|
* 可以帮助我们创建出可重用、易装配的组件。
|
||||||
|
* 可以减少嵌套,降低特定性。
|
||||||
|
* 可以帮助我们创建出可扩展的样式表。
|
||||||
|
|
||||||
|
**OOCSS**,也就是 “Object Oriented CSS(面向对象的CSS)”,是一种写 CSS 的方法,其思想就是鼓励你把样式表看作“对象”的集合:创建可重用性、可重复性的代码段让你可以在整个网站中多次使用。
|
||||||
|
|
||||||
|
参考资料:
|
||||||
|
|
||||||
|
* Nicole Sullivan 的 [OOCSS wiki](https://github.com/stubbornella/oocss/wiki)
|
||||||
|
* Smashing Magazine 的 [Introduction to OOCSS](http://www.smashingmagazine.com/2011/12/12/an-introduction-to-object-oriented-css-oocss/)
|
||||||
|
|
||||||
|
**BEM**,也就是 “Block-Element-Modifier”,是一种用于 HTML 和 CSS 类名的_命名约定_。BEM 最初是由 Yandex 提出的,要知道他们拥有巨大的代码库和可伸缩性,BEM 就是为此而生的,并且可以作为一套遵循 OOCSS 的参考指导规范。
|
||||||
|
|
||||||
|
* CSS Trick 的 [BEM 101](https://css-tricks.com/bem-101/)
|
||||||
|
* Harry Roberts 的 [introduction to BEM](http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/)
|
||||||
|
|
||||||
|
**示例**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<article class="listing-card listing-card--featured">
|
||||||
|
|
||||||
|
<h1 class="listing-card__title">Adorable 2BR in the sunny Mission</h1>
|
||||||
|
|
||||||
|
<div class="listing-card__content">
|
||||||
|
<p>Vestibulum id ligula porta felis euismod semper.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</article>
|
||||||
|
```
|
||||||
|
|
||||||
|
```css
|
||||||
|
.listing-card { }
|
||||||
|
.listing-card--featured { }
|
||||||
|
.listing-card__title { }
|
||||||
|
.listing-card__content { }
|
||||||
|
```
|
||||||
|
|
||||||
|
* `.listing-card` 是一个块(block),表示高层次的组件。
|
||||||
|
* `.listing-card__title` 是一个元素(element),它属于 `.listing-card` 的一部分,因此块是由元素组成的。
|
||||||
|
* `.listing-card--featured` 是一个修饰符(modifier),表示这个块与 `.listing-card` 有着不同的状态或者变化。
|
||||||
|
|
||||||
|
<a name="id-selectors"></a>
|
||||||
|
### ID 选择器
|
||||||
|
|
||||||
|
在 CSS 中,虽然可以通过 ID 选择元素,但大家通常都会把这种方式列为反面教材。ID 选择器给你的规则声明带来了不必要的高[优先级](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity),而且 ID 选择器是不可重用的。
|
||||||
|
|
||||||
|
想要了解关于这个主题的更多内容,参见 [CSS Wizardry 的文章](http://csswizardry.com/2014/07/hacks-for-dealing-with-specificity/),文章中有关于如何处理优先级的内容。
|
||||||
|
|
||||||
|
<a name="javascript-hooks"></a>
|
||||||
|
### JavaScript 钩子
|
||||||
|
|
||||||
|
避免在 CSS 和 JavaScript 中绑定相同的类。否则开发者在重构时通常会出现以下情况:轻则浪费时间在对照查找每个要改变的类,重则因为害怕破坏功能而不敢作出更改。
|
||||||
|
|
||||||
|
我们推荐在创建用于特定 JavaScript 的类名时,添加 `.js-` 前缀:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<button class="btn btn-primary js-request-to-book">Request to Book</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="sass"></a>
|
||||||
|
## Sass
|
||||||
|
|
||||||
|
<a name="syntax"></a>
|
||||||
|
### 语法
|
||||||
|
|
||||||
|
* 使用 `.scss` 的语法,不使用 `.sass` 原本的语法。
|
||||||
|
* CSS 和 `@include` 声明按照以下逻辑排序(参见下文)
|
||||||
|
|
||||||
|
<a name="ordering-of-property-declarations"></a>
|
||||||
|
### 属性声明的排序
|
||||||
|
|
||||||
|
1. 属性声明
|
||||||
|
|
||||||
|
首先列出除去 `@include` 和嵌套选择器之外的所有属性声明。
|
||||||
|
|
||||||
|
```scss
|
||||||
|
.btn-green {
|
||||||
|
background: green;
|
||||||
|
font-weight: bold;
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. `@include` 声明
|
||||||
|
|
||||||
|
紧随后面的是 `@include`,这样可以使得整个选择器的可读性更高。
|
||||||
|
|
||||||
|
```scss
|
||||||
|
.btn-green {
|
||||||
|
background: green;
|
||||||
|
font-weight: bold;
|
||||||
|
@include transition(background 0.5s ease);
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 嵌套选择器
|
||||||
|
|
||||||
|
_如果有必要_用到嵌套选择器,把它们放到最后,在规则声明和嵌套选择器之间要加上空白,相邻嵌套选择器之间也要加上空白。嵌套选择器中的内容也要遵循上述指引。
|
||||||
|
|
||||||
|
```scss
|
||||||
|
.btn {
|
||||||
|
background: green;
|
||||||
|
font-weight: bold;
|
||||||
|
@include transition(background 0.5s ease);
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="variables"></a>
|
||||||
|
### 变量
|
||||||
|
|
||||||
|
变量名应使用破折号(例如 `$my-variable`)代替 camelCased 和 snake_cased 风格。对于仅用在当前文件的变量,可以在变量名之前添加下划线前缀(例如 `$_my-variable`)。
|
||||||
|
|
||||||
|
<a name="mixins"></a>
|
||||||
|
### Mixins
|
||||||
|
|
||||||
|
为了让代码遵循 DRY 原则(Don't Repeat Yourself)、增强清晰性或抽象化复杂性,应该使用 mixin,这与那些命名良好的函数的作用是异曲同工的。虽然 mixin 可以不接收参数,但要注意,假如你不压缩负载(比如通过 gzip),这样会导致最终的样式包含不必要的代码重复。
|
||||||
|
|
||||||
|
<a name="extend-directive"></a>
|
||||||
|
### 扩展指令
|
||||||
|
|
||||||
|
应避免使用 `@extend` 指令,因为它并不直观,而且具有潜在风险,特别是用在嵌套选择器的时候。即便是在顶层占位符选择器使用扩展,如果选择器的顺序最终会改变,也可能会导致问题。(比如,如果它们存在于其他文件,而加载顺序发生了变化)。其实,使用 @extend 所获得的大部分优化效果,gzip 压缩已经帮助你做到了,因此你只需要通过 mixin 让样式表更符合 DRY 原则就足够了。
|
||||||
|
|
||||||
|
<a name="nested-selectors"></a>
|
||||||
|
### 嵌套选择器
|
||||||
|
|
||||||
|
**请不要让嵌套选择器的深度超过 3 层!**
|
||||||
|
|
||||||
|
```scss
|
||||||
|
.page-container {
|
||||||
|
.content {
|
||||||
|
.profile {
|
||||||
|
// STOP!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
当遇到以上情况的时候,你也许是这样写 CSS 的:
|
||||||
|
|
||||||
|
* 与 HTML 强耦合的(也是脆弱的)*—或者—*
|
||||||
|
* 过于具体(强大)*—或者—*
|
||||||
|
* 没有重用
|
||||||
|
|
||||||
|
|
||||||
|
再说一遍: **永远不要嵌套 ID 选择器!**
|
||||||
|
|
||||||
|
如果你始终坚持要使用 ID 选择器(劝你三思),那也不应该嵌套它们。如果你正打算这么做,你需要先重新检查你的标签,或者指明原因。如果你想要写出风格良好的 HTML 和 CSS,你是**不**应该这样做的。
|
|
@ -0,0 +1,414 @@
|
||||||
|
# HTML 规范指南
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
1. [通用约定](#general)
|
||||||
|
* [分离](#separate)
|
||||||
|
* [缩进](#indentation)
|
||||||
|
* [编码](#encoding)
|
||||||
|
* [小写](#lowercase)
|
||||||
|
* [注释](#comment)
|
||||||
|
* [待办事项](#todo)
|
||||||
|
* [省略嵌入式资源协议头](#protocol-relative-url)
|
||||||
|
* [代码有效性](#validator)
|
||||||
|
1. [HTML约定](#html)
|
||||||
|
* [文档类型](#doctype)
|
||||||
|
* [省略type属性](#type)
|
||||||
|
* [省略属性值](#attribute)
|
||||||
|
* [用双引号包裹属性值](#quots)
|
||||||
|
* [嵌套](#nest)
|
||||||
|
* [标签闭合](#close-tag)
|
||||||
|
* [多媒体替代方案](#perceivable)
|
||||||
|
* [有效操作](#friendly)
|
||||||
|
* [按模块添加注释](#html-comment)
|
||||||
|
* [格式](#format)
|
||||||
|
* [语义化标签](#semantic)
|
||||||
|
* [模块化](#html-module)
|
||||||
|
1. [图像约定](#img)
|
||||||
|
* [图像压缩](#img-compress)
|
||||||
|
* [背景图](#background-image)
|
||||||
|
* [前景图](#image)
|
||||||
|
* [Sprite](#sprite)
|
||||||
|
* [图标](#icon)
|
||||||
|
|
||||||
|
<a name="general"></a>
|
||||||
|
## 通用约定
|
||||||
|
|
||||||
|
<a name="separate"></a>
|
||||||
|
### 分离
|
||||||
|
|
||||||
|
结构(HTML)、表现(CSS)、行为分离(JavaScript)
|
||||||
|
|
||||||
|
> 将结构与表现、行为分离,保证它们之间的最小耦合,这对前期开发和后期维护都至关重要。
|
||||||
|
|
||||||
|
<a name="file-name"></a>
|
||||||
|
### 文件命名
|
||||||
|
|
||||||
|
* CSS模块文件,其文件名尽量与模块名一致;
|
||||||
|
|
||||||
|
> 假定有一个HTML页面叫 `product.html`,那么其相对应的CSS页面文件名应该为:`product.css`
|
||||||
|
|
||||||
|
|
||||||
|
<a name="indentation"></a>
|
||||||
|
### 缩进
|
||||||
|
|
||||||
|
使用2个空格来进行缩进。
|
||||||
|
|
||||||
|
<a name="encoding"></a>
|
||||||
|
### 编码
|
||||||
|
|
||||||
|
* 以 UTF-8 无 BOM 编码作为文件格式。
|
||||||
|
* 在HTML中文档中用 `<meta charset="utf-8" />` 来指定编码。
|
||||||
|
* 为每个CSS文档显示的定义编码,在文档首行定义 `@charset "utf-8";`
|
||||||
|
|
||||||
|
> 在 Sass 中,如果文档中出现中文,却未显示定义编码,将会编译出错,为了统一各种写法,且提前规避错误几率,统一要求每个CSS文档都需要定义编码
|
||||||
|
|
||||||
|
<a name="lowercase"></a>
|
||||||
|
### 小写
|
||||||
|
|
||||||
|
* 所有的HTML标签必须小写。
|
||||||
|
* 所有的HTML属性必须小写。
|
||||||
|
* 所有的样式名及规则必须小写。
|
||||||
|
|
||||||
|
<a name="comment"></a>
|
||||||
|
### 注释
|
||||||
|
|
||||||
|
尽可能的为你的代码写上注释。解释为什么要这样写,它是新鲜的方案还是解决了什么问题。
|
||||||
|
|
||||||
|
<a name="todo"></a>
|
||||||
|
### 待办事项
|
||||||
|
|
||||||
|
用 TODO 标示待办事项和正在开发的条目
|
||||||
|
|
||||||
|
<!-- TODO: 图文混排 -->
|
||||||
|
<div class="g-imgtext">
|
||||||
|
<img src="1.png" alt="" />
|
||||||
|
...
|
||||||
|
|
||||||
|
/* TODO: 图文混排 comm: g-imgtext */
|
||||||
|
.g-imgtext { sRules; }
|
||||||
|
|
||||||
|
<a name="protocol-relative-url"></a>
|
||||||
|
### 省略嵌入式资源协议头
|
||||||
|
|
||||||
|
省略图像、媒体文件、样式表和脚本等URL协议头部声明 ( http: , https: )。如果不是这两个声明的URL则不省略。
|
||||||
|
|
||||||
|
省略协议声明,使URL成相对地址,防止内容混淆问题和导致小文件重复下载(这个主要是指http和https交杂的场景中)。
|
||||||
|
|
||||||
|
不推荐:
|
||||||
|
|
||||||
|
<script src="http://www.google.com/js/gweb/analytics/autotrack.js"></script>
|
||||||
|
|
||||||
|
推荐:
|
||||||
|
|
||||||
|
<script src="//www.google.com/js/gweb/analytics/autotrack.js"></script>
|
||||||
|
|
||||||
|
不推荐:
|
||||||
|
|
||||||
|
```
|
||||||
|
.example {
|
||||||
|
background: url(http://www.google.com/images/example);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
推荐:
|
||||||
|
|
||||||
|
```
|
||||||
|
.example {
|
||||||
|
background: url(//www.google.com/images/example);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> 注:省略协议头在IE7-8下会有一点小问题,外部CSS文件(link和@import)会被下载两遍,所以该条目的约定看具体项目。
|
||||||
|
|
||||||
|
<a name="validator"></a>
|
||||||
|
### 代码有效性
|
||||||
|
|
||||||
|
* 使用 [W3C HTML Validator](http://validator.w3.org/) 来验证你的HTML代码有效性。
|
||||||
|
* 使用 [W3C CSS Validator](http://jigsaw.w3.org/css-validator/) 来验证你的CSS代码有效性。
|
||||||
|
|
||||||
|
> 代码验证不是最终目的,真的目的在于让开发者在经过多次的这种验证过程后,能够深刻理解到怎样的语法或写法是非标准和不推荐的,即使在某些场景下被迫要使用非标准写法,也可以做到心中有数。
|
||||||
|
|
||||||
|
<a name="html"></a>
|
||||||
|
## HTML约定
|
||||||
|
|
||||||
|
<a name="doctype"></a>
|
||||||
|
### 文档类型
|
||||||
|
|
||||||
|
* 统一使用HTML5的标准文档类型:`<!DOCTYPE html>`。
|
||||||
|
|
||||||
|
> HTML5文档类型具备前后兼容的特质,并且易记易书写
|
||||||
|
|
||||||
|
* 在文档doctype申明之前,不允许加上任何非空字符。
|
||||||
|
|
||||||
|
> 任何出现在doctype申明之前的字符都将使得你的HTML文档进入非标准模式
|
||||||
|
|
||||||
|
* 不允许添加 `<meta>` 标签强制改变文档模式。
|
||||||
|
|
||||||
|
> 避免出现不可控的问题
|
||||||
|
|
||||||
|
<a name="type"></a>
|
||||||
|
### 省略type属性
|
||||||
|
|
||||||
|
在调用CSS和JavaScript时,可以将type属性省略不写
|
||||||
|
|
||||||
|
不允许:
|
||||||
|
|
||||||
|
<link type="text/css" rel="stylesheet" href="base.css" />
|
||||||
|
<script type="text/javascript" src="base.js"></script>
|
||||||
|
|
||||||
|
应该:
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="base.css" />
|
||||||
|
<script src="base.js"></script>
|
||||||
|
|
||||||
|
> 因为HTML5在引入CSS时,默认type值为text/css;在引入JavaScript时,默认type值为text/javascript
|
||||||
|
|
||||||
|
<a name="attribute"></a>
|
||||||
|
### 省略属性值
|
||||||
|
|
||||||
|
非必须属性值可以省略
|
||||||
|
|
||||||
|
不允许:
|
||||||
|
|
||||||
|
<input type="text" readonly="readonly" />
|
||||||
|
<input type="text" disabled="disabled" />
|
||||||
|
|
||||||
|
应该:
|
||||||
|
|
||||||
|
<input type="text" readonly />
|
||||||
|
<input type="text" disabled />
|
||||||
|
|
||||||
|
> 这里的 readonly 和 disabled 属性的值是非必须的,可以省略不写,我们知道HTML5表单元素新增了很多类似的属性,如: required
|
||||||
|
|
||||||
|
<a name="quots"></a>
|
||||||
|
### 用双引号包裹属性值
|
||||||
|
|
||||||
|
所有的标签属性值必须要用双引号包裹,同时也不允许有的用双引号,有的用单引号的情况
|
||||||
|
|
||||||
|
不允许:
|
||||||
|
|
||||||
|
<a href=http://www.qunar.com class=home>去哪儿网</a>
|
||||||
|
|
||||||
|
应该:
|
||||||
|
|
||||||
|
<a href="http://www.qunar.com" class="home">去哪儿网</a>
|
||||||
|
|
||||||
|
<a name="nest"></a>
|
||||||
|
### 嵌套
|
||||||
|
|
||||||
|
所有元素必须正确嵌套
|
||||||
|
|
||||||
|
* 不允许交叉。
|
||||||
|
|
||||||
|
不允许:
|
||||||
|
|
||||||
|
<span><dfn>交叉嵌套</span></dfn>
|
||||||
|
|
||||||
|
应该:
|
||||||
|
|
||||||
|
<span><dfn>交叉嵌套</dfn></span>
|
||||||
|
|
||||||
|
* 不允许非法的子元素嵌套。
|
||||||
|
|
||||||
|
不允许:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<h3>xx列表</h3>
|
||||||
|
<li>asdasdsdasd</li>
|
||||||
|
<li>asdasdsdasd</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
应该:
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3>xx列表</h3>
|
||||||
|
<ul>
|
||||||
|
<li>asdasdsdasd</li>
|
||||||
|
<li>asdasdsdasd</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
* 不推荐inline元素包含block元素。
|
||||||
|
|
||||||
|
不推荐:
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<h1>这是一个块级h1元素</h1>
|
||||||
|
<p>这是一个块级p元素</p>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
推荐:
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>这是一个块级h1元素</h1>
|
||||||
|
<p>这是一个块级p元素</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
规则可参考:
|
||||||
|
|
||||||
|
> HTML5: [嵌套规则](http://www.w3.org/TR/html5/)
|
||||||
|
>
|
||||||
|
> 举个例子,在HTML5中,a元素同时属于 Flow content, Phrasing content, Interactive content, Palpable content 4个分类,那些子元素是 phrasing 元素的元素可以是 a 的父元素,a 允许的子元素是以它的父元素允许的子元素为准,但不能包含 interactive 元素。
|
||||||
|
|
||||||
|
<a name="close-tag"></a>
|
||||||
|
### 标签闭合
|
||||||
|
|
||||||
|
所有标签必须闭合
|
||||||
|
|
||||||
|
不允许:
|
||||||
|
|
||||||
|
<div>balabala...
|
||||||
|
<link rel="stylesheet" href="*.css">
|
||||||
|
|
||||||
|
应该:
|
||||||
|
|
||||||
|
<div>balabala...</div>
|
||||||
|
<link rel="stylesheet" href="*.css" />
|
||||||
|
|
||||||
|
> 虽然有些标记没有要求必须关闭,但是为了避免出错的几率,要求必须全部关闭,省去判断某标记是否需要关闭的时间
|
||||||
|
|
||||||
|
<a name="perceivable"></a>
|
||||||
|
### 多媒体替代方案
|
||||||
|
|
||||||
|
* 为img元素加上alt属性。
|
||||||
|
* 为视频内容提供音轨替代。
|
||||||
|
* 为音频内容提供字母替代等等。
|
||||||
|
|
||||||
|
不推荐:
|
||||||
|
|
||||||
|
<img src="banner.jpg" />
|
||||||
|
|
||||||
|
推荐:
|
||||||
|
|
||||||
|
<img src="banner.jpg" alt="520即将到来,爱就大声说出来" />
|
||||||
|
|
||||||
|
> alt属性的内容为对该图片的简要描述,这对于盲人用户和图像损毁都非常有意义,即无障碍。对于纯粹的装饰性图片,alt属性值可以留空,如 alt=""
|
||||||
|
|
||||||
|
<a name="friendly"></a>
|
||||||
|
### 有效操作
|
||||||
|
|
||||||
|
为表单元素label加上for属性
|
||||||
|
|
||||||
|
不允许:
|
||||||
|
|
||||||
|
<input type="radio" name="color" value="0" /><label>蓝色</label>
|
||||||
|
<input type="radio" name="color" value="1" /><label>粉色</label>
|
||||||
|
|
||||||
|
应该:
|
||||||
|
|
||||||
|
<input type="radio" id="blue" name="color" value="0" /><label for="blue">蓝色</label>
|
||||||
|
<input type="radio" id="pink" name="color" value="1" /><label for="pink">粉色</label>
|
||||||
|
|
||||||
|
> for属性能让点击label标签的时候,同时focus到对应的 input 和 textarea上,增加响应区域
|
||||||
|
|
||||||
|
<a name="html-comment"></a>
|
||||||
|
### 按模块添加注释
|
||||||
|
|
||||||
|
在每个模块开始和结束的地方添加注释
|
||||||
|
|
||||||
|
<!-- 新闻列表模块 -->
|
||||||
|
<div class="m-news g-mod"
|
||||||
|
...
|
||||||
|
<!-- /新闻列表模块 -->
|
||||||
|
|
||||||
|
<!-- 排行榜模块 -->
|
||||||
|
<div class="m-topic g-mod"
|
||||||
|
...
|
||||||
|
<!-- /排行榜模块 -->
|
||||||
|
|
||||||
|
> 注释内容左右两边保留和注释符号有1个空格位,在注释内容内不允许再出现中划线“-”,某些浏览器会报错。
|
||||||
|
>
|
||||||
|
> 注释风格保持与原生HTML的语法相似:成对出现 `<!-- comment --><!-- /comment -->`
|
||||||
|
|
||||||
|
<a name="format"></a>
|
||||||
|
### 格式
|
||||||
|
|
||||||
|
* 将每个块元素、列表元素或表格元素都放在新行。
|
||||||
|
* inline元素视情况换行,以长度不超过编辑器一屏为宜。
|
||||||
|
* 每个子元素都需要相对其父级缩进(参见[缩进约定](#indentation))。
|
||||||
|
|
||||||
|
不推荐:
|
||||||
|
|
||||||
|
<div><h1>asdas</h1><p>dff<em>asd</em>asda<span>sds</span>dasdasd</p></div>
|
||||||
|
|
||||||
|
推荐:
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>asdas</h1>
|
||||||
|
<p>dff<em>asd</em>asda<span>sds</span>dasdasd</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a name="semantic"></a>
|
||||||
|
### 语义化标签
|
||||||
|
|
||||||
|
* 根据HTML元素的本身用途去使用它们。
|
||||||
|
* 禁止使用被废弃的用于表现的标签,如 center, font 等。
|
||||||
|
* 部分在XHTML1中被废弃的标签,在HTML5中被重新赋予了新的语义,在选用时请先弄清其语义,如:b, i, u等。
|
||||||
|
|
||||||
|
不允许:
|
||||||
|
|
||||||
|
<p>标题</p>
|
||||||
|
|
||||||
|
应该:
|
||||||
|
|
||||||
|
<h1>标题</h1>
|
||||||
|
|
||||||
|
> 虽然使用p标签,也可以通过CSS去定义它的外观和标题相同,但p标签本身的并不是表示标题,而是表示文本段落
|
||||||
|
|
||||||
|
> 参阅:[HTML5 Elements](http://www.w3.org/TR/html5/)
|
||||||
|
|
||||||
|
<a name="html-module"></a>
|
||||||
|
### 模块化
|
||||||
|
|
||||||
|
* 每个模块必须有一个模块名。
|
||||||
|
* 每个模块的基本组成部分应该一致。
|
||||||
|
* 模块的子节点类名需带上模块名(防止模块间嵌套时产生不必要的覆盖)。
|
||||||
|
* 孙辈节点无需再带模块名。
|
||||||
|
|
||||||
|
代码如:
|
||||||
|
|
||||||
|
<section class="m-detail">
|
||||||
|
<header class="m-detail-hd">
|
||||||
|
<h1 class="title">模块标题</h1>
|
||||||
|
</header>
|
||||||
|
<div class="m-detail-bd">
|
||||||
|
<p class="info">一些实际内容</p>
|
||||||
|
</div>
|
||||||
|
<footer class="m-detail-ft">
|
||||||
|
<a href="#" class="more">更多</a>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
> 其中 `.m-detail-hd`, `.m-detail-bd`, `.m-detail-ft` 为可选,视具体模块情况决定是否需要抽象为这种 **头,中,尾** 的结构
|
||||||
|
|
||||||
|
<a name="img"></a>
|
||||||
|
## 图像约定
|
||||||
|
|
||||||
|
<a name="img-compress"></a>
|
||||||
|
### 图像压缩
|
||||||
|
|
||||||
|
所有图片必须经过一定的压缩和优化才能发布。
|
||||||
|
|
||||||
|
<a name="background-image"></a>
|
||||||
|
### 背景图
|
||||||
|
|
||||||
|
使用PNG格式而不是GIF格式,因为PNG格式色彩更丰富,还能提供更好的压缩比。
|
||||||
|
|
||||||
|
<a name="image"></a>
|
||||||
|
### 前景图
|
||||||
|
|
||||||
|
* 内容图片建议使用JPG,可以拥有更好地显示效果。
|
||||||
|
* 装饰性图片使用PNG。
|
||||||
|
|
||||||
|
<a name="sprite"></a>
|
||||||
|
### Sprite
|
||||||
|
|
||||||
|
* CSS Sprite是一种将数个图片合成为一张大图的技术(既可以是背景图也可以是前景图),然后通过偏移来进行图像位置选取。
|
||||||
|
* CSS Sprite可以减少http请求。
|
||||||
|
|
||||||
|
<a name="icon"></a>
|
||||||
|
### 图标
|
||||||
|
|
||||||
|
* 如兼容 IE 低版本使用 字体图标 而非 css Sprite。
|
||||||
|
* 更建议使用 svg Symbol 方式作为图标,相比字体图标,拥有更高的的扩展性和维护性,而且还可以控制局部颜色。
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,58 @@
|
||||||
|
# ESLint 配置及规则说明
|
||||||
|
|
||||||
|
### 一、包含:
|
||||||
|
|
||||||
|
**eslintrc.json**: 该文件可以是你项目中有且仅有ESLint的配置文件,包含简要的规则解释。
|
||||||
|
|
||||||
|
### 二、配置文件使用说明
|
||||||
|
|
||||||
|
#### 1. 安装依赖:
|
||||||
|
|
||||||
|
在`package.json`文件中添加如下依赖(如果没有`package.son`文件需首先通过`npm init` 创建`package.son ` 文件):
|
||||||
|
|
||||||
|
``` json
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-core": "^6.5.2",
|
||||||
|
"babel-eslint": "^4.1.8",
|
||||||
|
"eslint": "^2.1.0",
|
||||||
|
"eslint-plugin-promise": "^1.0.8",
|
||||||
|
"eslint-plugin-standard": "^1.3.2"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
运行如下命令:
|
||||||
|
|
||||||
|
> npm install
|
||||||
|
|
||||||
|
#### 2. 将文件夹中的eslintrc.json文件放置在项目根目录
|
||||||
|
|
||||||
|
并将`eslintrc.json`重命名为`.eslintrc`(或者直接使用文件夹中的`.eslintrc`文件)
|
||||||
|
|
||||||
|
#### 3. 修改配置文件
|
||||||
|
|
||||||
|
根据自己项目需要,在配置文件中`globals`配置项中添加项目所需全局变量:举个栗子:
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"globals": {
|
||||||
|
"document": true,
|
||||||
|
"navigator": true,
|
||||||
|
"window": true,
|
||||||
|
"angular":true // 添加项目所需没有申明的全局变量
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4. 让ESLint运行起来
|
||||||
|
|
||||||
|
修改`package.json`文件。在`script` 配置项中添加如下代码:举个栗子:
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"scripts": {
|
||||||
|
"lint": "eslint app.jsx test" //其中app.jsx test需要替换成你项目需要检测的文件或文件夹
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
命令行运行如下代码:
|
||||||
|
|
||||||
|
> npm run lint
|
||||||
|
|
||||||
|
好了,现在就可以在终端看检测结果了。
|
|
@ -0,0 +1,239 @@
|
||||||
|
{
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 6,
|
||||||
|
"ecmaFeatures": {
|
||||||
|
"experimentalObjectRestSpread": true,
|
||||||
|
"jsx": true
|
||||||
|
},
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es6": true,
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"plugins": [
|
||||||
|
"standard",
|
||||||
|
"promise"
|
||||||
|
],
|
||||||
|
|
||||||
|
"globals": {
|
||||||
|
"document": true,
|
||||||
|
"navigator": true,
|
||||||
|
"window": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"parser": "babel-eslint",
|
||||||
|
|
||||||
|
"rules": {
|
||||||
|
// 在定义对象的时候,getter/setter需要同时出现
|
||||||
|
"accessor-pairs": 2,
|
||||||
|
// 箭头函数中,在需要的时候,在参数外使用小括号(只有一个参数时,可以不适用括号,其它情况下都需要使用括号)
|
||||||
|
"arrow-parens": [2, "as-needed"],
|
||||||
|
// 箭头函数中的箭头前后需要留空格
|
||||||
|
"arrow-spacing": [2, { "before": true, "after": true }],
|
||||||
|
// 如果代码块是单行的时候,代码块内部前后需要留一个空格
|
||||||
|
"block-spacing": [2, "always"],
|
||||||
|
// 大括号语法采用『1tbs』,允许单行样式
|
||||||
|
"brace-style": [2, "1tbs", { "allowSingleLine": true }],
|
||||||
|
// 在定义对象或数组时,最后一项不能加逗号
|
||||||
|
"comma-dangle": [2, "never"],
|
||||||
|
// 在写逗号时,逗号前面不需要加空格,而逗号后面需要添加空格
|
||||||
|
"comma-spacing": [2, { "before": false, "after": true }],
|
||||||
|
// 如果逗号可以放在行首或行尾时,那么请放在行尾
|
||||||
|
"comma-style": [2, "last"],
|
||||||
|
// 在constructor函数中,如果classes是继承其他class,那么请使用super。否者不使用super
|
||||||
|
"constructor-super": 2,
|
||||||
|
// 在if-else语句中,如果if或else语句后面是多行,那么必须加大括号。如果是单行就应该省略大括号。
|
||||||
|
"curly": [2, "multi-line"],
|
||||||
|
// 该规则规定了.应该放置的位置,
|
||||||
|
"dot-location": [2, "property"],
|
||||||
|
// 该规则要求代码最后面需要留一空行,(仅需要留一空行)
|
||||||
|
"eol-last": 2,
|
||||||
|
// 使用=== !== 代替== != .
|
||||||
|
"eqeqeq": [2, "allow-null"],
|
||||||
|
// 该规则规定了generator函数中星号两边的空白。
|
||||||
|
"generator-star-spacing": [2, { "before": true, "after": true }],
|
||||||
|
// 规定callback 如果有err参数,只能写出err 或者 error .
|
||||||
|
"handle-callback-err": [2, "^(err|error)$" ],
|
||||||
|
// 这个就是关于用什么来缩进了,规定使用tab 来进行缩进,switch中case也需要一个tab .
|
||||||
|
"indent": [2, "tab", { "SwitchCase": 1 }],
|
||||||
|
// keyword 前后需要空格
|
||||||
|
"keyword-spacing": [2, {"before": true, "after": true, "overrides": {}}],
|
||||||
|
// 该规则规定了在对象字面量语法中,key和value之间的空白,冒号前不要空格,冒号后面需要一个空格
|
||||||
|
"key-spacing": [2, { "beforeColon": false, "afterColon": true }],
|
||||||
|
// 构造函数首字母大写
|
||||||
|
"new-cap": [2, { "newIsCap": true, "capIsNew": false }],
|
||||||
|
// 在使用构造函数时候,函数调用的圆括号不能够省略
|
||||||
|
"new-parens": 2,
|
||||||
|
// 禁止使用Array构造函数
|
||||||
|
"no-array-constructor": 2,
|
||||||
|
// 禁止使用arguments.caller和arguments.callee
|
||||||
|
"no-caller": 2,
|
||||||
|
// 禁止覆盖class命名,也就是说变量名不要和class名重名
|
||||||
|
"no-class-assign": 2,
|
||||||
|
// 在条件语句中不要使用赋值语句
|
||||||
|
"no-cond-assign": 2,
|
||||||
|
// const申明的变量禁止修改
|
||||||
|
"no-const-assign": 2,
|
||||||
|
// 在正则表达式中禁止使用控制符(详见官网)
|
||||||
|
"no-control-regex": 2,
|
||||||
|
// 禁止使用debugger语句
|
||||||
|
"no-debugger": 2,
|
||||||
|
// 禁止使用delete删除var申明的变量
|
||||||
|
"no-delete-var": 2,
|
||||||
|
// 函数参数禁止重名
|
||||||
|
"no-dupe-args": 2,
|
||||||
|
// class中的成员禁止重名
|
||||||
|
"no-dupe-class-members": 2,
|
||||||
|
// 在对象字面量中,禁止使用重复的key
|
||||||
|
"no-dupe-keys": 2,
|
||||||
|
// 在switch语句中禁止重复的case
|
||||||
|
"no-duplicate-case": 2,
|
||||||
|
// 禁止使用不匹配任何字符串的正则表达式
|
||||||
|
"no-empty-character-class": 2,
|
||||||
|
// 禁止使用eval函数
|
||||||
|
"no-eval": 2,
|
||||||
|
// 禁止对catch语句中的参数进行赋值
|
||||||
|
"no-ex-assign": 2,
|
||||||
|
// 禁止扩展原生对象
|
||||||
|
"no-extend-native": 2,
|
||||||
|
// 禁止在不必要的时候使用bind函数
|
||||||
|
"no-extra-bind": 2,
|
||||||
|
// 在一个本来就会自动转化为布尔值的上下文中就没必要再使用!! 进行强制转化了。
|
||||||
|
"no-extra-boolean-cast": 2,
|
||||||
|
// 禁止使用多余的圆括号
|
||||||
|
"no-extra-parens": [2, "functions"],
|
||||||
|
// 这条规则,简单来说就是在case语句中尽量加break,避免不必要的fallthrough错误,如果需要fall through,那么看官网。
|
||||||
|
"no-fallthrough": 2,
|
||||||
|
// 简单来说不要写这样的数字.2 2.。应该写全,2.2 2.0 .
|
||||||
|
"no-floating-decimal": 2,
|
||||||
|
// 禁止对函数名重新赋值
|
||||||
|
"no-func-assign": 2,
|
||||||
|
// 禁止使用类eval的函数。
|
||||||
|
"no-implied-eval": 2,
|
||||||
|
// 禁止在代码块中定义函数(下面的规则仅限制函数)
|
||||||
|
"no-inner-declarations": [2, "functions"],
|
||||||
|
// RegExp构造函数中禁止使用非法正则语句
|
||||||
|
"no-invalid-regexp": 2,
|
||||||
|
// 禁止使用不规则的空白符
|
||||||
|
"no-irregular-whitespace": 2,
|
||||||
|
// 禁止使用__iterator__属性
|
||||||
|
"no-iterator": 2,
|
||||||
|
// label和var申明的变量不能重名
|
||||||
|
"no-label-var": 2,
|
||||||
|
// 禁止使用label语句
|
||||||
|
"no-labels": [2, {"allowLoop": false, "allowSwitch": false}],
|
||||||
|
// 禁止使用没有必要的嵌套代码块
|
||||||
|
"no-lone-blocks": 2,
|
||||||
|
// 不要把空格和tab混用
|
||||||
|
"no-mixed-spaces-and-tabs": 2,
|
||||||
|
// 顾名思义,该规则保证了在逻辑表达式、条件表达式、
|
||||||
|
// 申明语句、数组元素、对象属性、sequences、函数参数中不使用超过一个的空白符。
|
||||||
|
"no-multi-spaces": 2,
|
||||||
|
// 该规则保证了字符串不分两行书写。
|
||||||
|
"no-multi-str": 2,
|
||||||
|
// 空行不能够超过2行
|
||||||
|
"no-multiple-empty-lines": [2, { "max": 2 }],
|
||||||
|
// 该规则保证了不重写原生对象。
|
||||||
|
"no-native-reassign": 2,
|
||||||
|
// 在in操作符左边的操作项不能用! 例如这样写不对的:if ( !a in b) { // dosomething }
|
||||||
|
"no-negated-in-lhs": 2,
|
||||||
|
// 当我们使用new操作符去调用构造函数时,需要把调用结果赋值给一个变量。
|
||||||
|
"no-new": 2,
|
||||||
|
// 该规则保证了不使用new Function(); 语句。
|
||||||
|
"no-new-func": 2,
|
||||||
|
// 不要通过new Object(),来定义对象
|
||||||
|
"no-new-object": 2,
|
||||||
|
// 禁止把require方法和new操作符一起使用。
|
||||||
|
"no-new-require": 2,
|
||||||
|
// 当定义字符串、数字、布尔值就不要使用构造函数了,String、Number、Boolean
|
||||||
|
"no-new-wrappers": 2,
|
||||||
|
// 禁止无意得把全局对象当函数调用了,比如下面写法错误的:Math(), JSON()
|
||||||
|
"no-obj-calls": 2,
|
||||||
|
// 不要使用八进制的语法。
|
||||||
|
"no-octal": 2,
|
||||||
|
// 用的少,见官网。http://eslint.org/docs/rules/
|
||||||
|
"no-octal-escape": 2,
|
||||||
|
// 不要使用__proto__
|
||||||
|
"no-proto": 2,
|
||||||
|
// 不要重复申明一个变量
|
||||||
|
"no-redeclare": 2,
|
||||||
|
// 正则表达式中不要使用空格
|
||||||
|
"no-regex-spaces": 2,
|
||||||
|
// return语句中不要写赋值语句
|
||||||
|
"no-return-assign": 2,
|
||||||
|
// 不要和自身作比较
|
||||||
|
"no-self-compare": 2,
|
||||||
|
// 不要使用逗号操作符,详见官网
|
||||||
|
"no-sequences": 2,
|
||||||
|
// 禁止对一些关键字或者保留字进行赋值操作,比如NaN、Infinity、undefined、eval、arguments等。
|
||||||
|
"no-shadow-restricted-names": 2,
|
||||||
|
// 函数调用时,圆括号前面不能有空格
|
||||||
|
"no-spaced-func": 2,
|
||||||
|
// 禁止使用稀疏数组
|
||||||
|
"no-sparse-arrays": 2,
|
||||||
|
// 在调用super之前不能使用this对象
|
||||||
|
"no-this-before-super": 2,
|
||||||
|
// 严格限制了抛出错误的类型,简单来说只能够抛出Error生成的错误。但是这条规则并不能够保证你只能够
|
||||||
|
// 抛出Error错误。详细见官网
|
||||||
|
"no-throw-literal": 2,
|
||||||
|
// 行末禁止加空格
|
||||||
|
"no-trailing-spaces": 2,
|
||||||
|
// 禁止使用没有定义的变量,除非在/*global*/已经申明
|
||||||
|
"no-undef": 2,
|
||||||
|
// 禁止把undefined赋值给一个变量
|
||||||
|
"no-undef-init": 2,
|
||||||
|
// 禁止在不需要分行的时候使用了分行
|
||||||
|
"no-unexpected-multiline": 2,
|
||||||
|
// 禁止使用没有必要的三元操作符,因为用些三元操作符可以使用其他语句替换
|
||||||
|
"no-unneeded-ternary": [2, { "defaultAssignment": false }],
|
||||||
|
// 没有执行不到的代码
|
||||||
|
"no-unreachable": 2,
|
||||||
|
// 没有定义了没有被使用到的变量
|
||||||
|
"no-unused-vars": [2, { "vars": "all", "args": "none" }],
|
||||||
|
// 禁止在不需要使用call()或者apply()的时候使用了这两个方法
|
||||||
|
"no-useless-call": 2,
|
||||||
|
// 不要使用with语句
|
||||||
|
"no-with": 2,
|
||||||
|
// 在某些场景只能使用一个var来申明变量
|
||||||
|
"one-var": [2, { "initialized": "never" }],
|
||||||
|
// 在进行断行时,操作符应该放在行首还是行尾。并且还可以对某些操作符进行重写。
|
||||||
|
"operator-linebreak": [2, "after", { "overrides": { "?": "before", ":": "before" } }],
|
||||||
|
// 使用单引号
|
||||||
|
"quotes": [2, "single", "avoid-escape"],
|
||||||
|
// 在使用parseInt() 方法时,需要传递第二个参数,来帮助解析,告诉方法解析成多少进制。
|
||||||
|
"radix": 2,
|
||||||
|
// 这就是分号党和非分号党关心的了,我们还是选择加分号
|
||||||
|
"semi": [2, "always"],
|
||||||
|
// 该规则规定了分号前后的空格,具体规定如下。
|
||||||
|
"semi-spacing": [2, { "before": false, "after": true }],
|
||||||
|
// 代码块前面需要加空格
|
||||||
|
"space-before-blocks": [2, "always"],
|
||||||
|
// 函数圆括号前面需要加空格
|
||||||
|
"space-before-function-paren": [2, "never"],
|
||||||
|
// 圆括号内部不需要加空格
|
||||||
|
"space-in-parens": [2, "never"],
|
||||||
|
// 操作符前后需要加空格
|
||||||
|
"space-infix-ops": 2,
|
||||||
|
// 一元操作符前后是否需要加空格,单词类操作符需要加,而非单词类操作符不用加
|
||||||
|
"space-unary-ops": [2, { "words": true, "nonwords": false }],
|
||||||
|
// 评论符号`/*` `//`,后面需要留一个空格
|
||||||
|
"spaced-comment": [2, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }],
|
||||||
|
// 推荐使用isNaN方法,而不要直接和NaN作比较
|
||||||
|
"use-isnan": 2,
|
||||||
|
// 在使用typeof操作符时,作比较的字符串必须是合法字符串eg:'string' 'object'
|
||||||
|
"valid-typeof": 2,
|
||||||
|
// 立即执行函数需要用圆括号包围
|
||||||
|
"wrap-iife": [2, "any"],
|
||||||
|
// yoda条件语句就是字面量应该写在比较操作符的左边,而变量应该写在比较操作符的右边。
|
||||||
|
// 而下面的规则要求,变量写在前面,字面量写在右边
|
||||||
|
"yoda": [2, "never"],
|
||||||
|
|
||||||
|
"standard/object-curly-even-spacing": [2, "either"],
|
||||||
|
"standard/array-bracket-even-spacing": [2, "either"],
|
||||||
|
"standard/computed-property-even-spacing": [2, "even"]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,572 @@
|
||||||
|
# React/JSX 规范指南
|
||||||
|
|
||||||
|
*算是最合理的 React/JSX 编码规范之一了*
|
||||||
|
|
||||||
|
## 内容目录
|
||||||
|
|
||||||
|
1. [基本规范](#basic-rules-基本规范)
|
||||||
|
1. [Class vs React.createClass vs stateless](#创建模块)
|
||||||
|
1. [命名](#naming-命名)
|
||||||
|
1. [声明模块](#declaration-声明模块)
|
||||||
|
1. [代码对齐](#alignment-代码对齐)
|
||||||
|
1. [单引号还是双引号](#quotes-单引号还是双引号)
|
||||||
|
1. [空格](#spacing-空格)
|
||||||
|
1. [属性](#props-属性)
|
||||||
|
1. [Refs引用](#refs)
|
||||||
|
1. [括号](#parentheses-括号)
|
||||||
|
1. [标签](#tags-标签)
|
||||||
|
1. [函数/方法](#methods-函数)
|
||||||
|
1. [模块生命周期](#ordering-react-模块生命周期)
|
||||||
|
1. [isMounted](#ismounted)
|
||||||
|
|
||||||
|
## Basic Rules 基本规范
|
||||||
|
|
||||||
|
- 每个文件只写一个模块.
|
||||||
|
- 但是多个[无状态模块](https://facebook.github.io/react/docs/reusable-components.html#stateless-functions)可以放在单个文件中. eslint: [`react/no-multi-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md#ignorestateless).
|
||||||
|
- 推荐使用JSX语法.
|
||||||
|
- 不要使用 `React.createElement`,除非从一个非JSX的文件中初始化你的app.
|
||||||
|
|
||||||
|
## 创建模块
|
||||||
|
Class vs React.createClass vs stateless
|
||||||
|
|
||||||
|
- 如果你的模块有内部状态或者是`refs`, 推荐使用 `class extends React.Component` 而不是 `React.createClass` ,除非你有充足的理由来使用这些方法.
|
||||||
|
eslint: [`react/prefer-es6-class`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md) [`react/prefer-stateless-function`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md)
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
const Listing = React.createClass({
|
||||||
|
// ...
|
||||||
|
render() {
|
||||||
|
return <div>{this.state.hello}</div>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// good
|
||||||
|
class Listing extends React.Component {
|
||||||
|
// ...
|
||||||
|
render() {
|
||||||
|
return <div>{this.state.hello}</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
如果你的模块没有状态或是没有引用`refs`, 推荐使用普通函数(非箭头函数)而不是类:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
class Listing extends React.Component {
|
||||||
|
render() {
|
||||||
|
return <div>{this.props.hello}</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bad (relying on function name inference is discouraged)
|
||||||
|
const Listing = ({ hello }) => (
|
||||||
|
<div>{hello}</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
// good
|
||||||
|
function Listing({ hello }) {
|
||||||
|
return <div>{hello}</div>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Naming 命名
|
||||||
|
|
||||||
|
- **扩展名**: React模块使用 `.jsx` 扩展名.
|
||||||
|
- **文件名**: 文件名使用驼峰式. 如, `ReservationCard.jsx`.
|
||||||
|
- **引用命名**: React模块名使用驼峰式命名,实例使用骆驼式命名. eslint: [`react/jsx-pascal-case`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md)
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
import reservationCard from './ReservationCard';
|
||||||
|
|
||||||
|
// good
|
||||||
|
import ReservationCard from './ReservationCard';
|
||||||
|
|
||||||
|
// bad
|
||||||
|
const ReservationItem = <ReservationCard />;
|
||||||
|
|
||||||
|
// good
|
||||||
|
const reservationItem = <ReservationCard />;
|
||||||
|
```
|
||||||
|
|
||||||
|
- **模块命名**: 模块使用当前文件名一样的名称. 比如 `ReservationCard.jsx` 应该包含名为 `ReservationCard`的模块. 但是,如果整个文件夹是一个模块,使用 `index.js`作为入口文件,然后直接使用 `index.js` 或者文件夹名作为模块的名称:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
import Footer from './Footer/Footer';
|
||||||
|
|
||||||
|
// bad
|
||||||
|
import Footer from './Footer/index';
|
||||||
|
|
||||||
|
// good
|
||||||
|
import Footer from './Footer';
|
||||||
|
```
|
||||||
|
- **高阶模块命名**: 对于生成一个新的模块,其中的模块名 `displayName` 应该为高阶模块名和传入模块名的组合. 例如, 高阶模块 `withFoo()`, 当传入一个 `Bar` 模块的时候, 生成的模块名 `displayName` 应该为 `withFoo(Bar)`.
|
||||||
|
|
||||||
|
> 为什么?一个模块的 `displayName` 可能会在开发者工具或者错误信息中使用到,因此有一个能清楚的表达这层关系的值能帮助我们更好的理解模块发生了什么,更好的Debug.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
export default function withFoo(WrappedComponent) {
|
||||||
|
return function WithFoo(props) {
|
||||||
|
return <WrappedComponent {...props} foo />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// good
|
||||||
|
export default function withFoo(WrappedComponent) {
|
||||||
|
function WithFoo(props) {
|
||||||
|
return <WrappedComponent {...props} foo />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrappedComponentName = WrappedComponent.displayName
|
||||||
|
|| WrappedComponent.name
|
||||||
|
|| 'Component';
|
||||||
|
|
||||||
|
WithFoo.displayName = `withFoo(${wrappedComponentName})`;
|
||||||
|
return WithFoo;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## Declaration 声明模块
|
||||||
|
|
||||||
|
- 不要使用 `displayName` 来命名React模块,而是使用引用来命名模块, 如 class 名称.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
export default React.createClass({
|
||||||
|
displayName: 'ReservationCard',
|
||||||
|
// stuff goes here
|
||||||
|
});
|
||||||
|
|
||||||
|
// good
|
||||||
|
export default class ReservationCard extends React.Component {
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Alignment 代码对齐
|
||||||
|
|
||||||
|
- 遵循以下的JSX语法缩进/格式. eslint: [`react/jsx-closing-bracket-location`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md)
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
<Foo superLongParam="bar"
|
||||||
|
anotherSuperLongParam="baz" />
|
||||||
|
|
||||||
|
// good, 有多行属性的话, 新建一行关闭标签
|
||||||
|
<Foo
|
||||||
|
superLongParam="bar"
|
||||||
|
anotherSuperLongParam="baz"
|
||||||
|
/>
|
||||||
|
|
||||||
|
// 若能在一行中显示, 直接写成一行
|
||||||
|
<Foo bar="bar" />
|
||||||
|
|
||||||
|
// 子元素按照常规方式缩进
|
||||||
|
<Foo
|
||||||
|
superLongParam="bar"
|
||||||
|
anotherSuperLongParam="baz"
|
||||||
|
>
|
||||||
|
<Quux />
|
||||||
|
</Foo>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quotes 单引号还是双引号
|
||||||
|
|
||||||
|
- 对于JSX属性值总是使用双引号(`"`), 其他均使用单引号. eslint: [`jsx-quotes`](http://eslint.org/docs/rules/jsx-quotes)
|
||||||
|
|
||||||
|
> 为什么? JSX属性 [不能包括转译的引号](http://eslint.org/docs/rules/jsx-quotes), 因此在双引号里包括像 `"don't"` 的属性值更容易输入.
|
||||||
|
> HTML属性也是用双引号,所以JSX属性也遵循同样的语法.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
<Foo bar='bar' />
|
||||||
|
|
||||||
|
// good
|
||||||
|
<Foo bar="bar" />
|
||||||
|
|
||||||
|
// bad
|
||||||
|
<Foo style={{ left: "20px" }} />
|
||||||
|
|
||||||
|
// good
|
||||||
|
<Foo style={{ left: '20px' }} />
|
||||||
|
```
|
||||||
|
|
||||||
|
## Spacing 空格
|
||||||
|
|
||||||
|
- 总是在自动关闭的标签前加一个空格,正常情况下也不需要换行.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
<Foo/>
|
||||||
|
|
||||||
|
// very bad
|
||||||
|
<Foo />
|
||||||
|
|
||||||
|
// bad
|
||||||
|
<Foo
|
||||||
|
/>
|
||||||
|
|
||||||
|
// good
|
||||||
|
<Foo />
|
||||||
|
```
|
||||||
|
|
||||||
|
- 不要在JSX `{}` 引用括号里两边加空格. eslint: [`react/jsx-curly-spacing`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-spacing.md)
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
<Foo bar={ baz } />
|
||||||
|
|
||||||
|
// good
|
||||||
|
<Foo bar={baz} />
|
||||||
|
```
|
||||||
|
|
||||||
|
## Props 属性
|
||||||
|
|
||||||
|
- JSX属性名使用骆驼式风格`camelCase`.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
<Foo
|
||||||
|
UserName="hello"
|
||||||
|
phone_number={12345678}
|
||||||
|
/>
|
||||||
|
|
||||||
|
// good
|
||||||
|
<Foo
|
||||||
|
userName="hello"
|
||||||
|
phoneNumber={12345678}
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
- 如果属性值为 `true`, 可以直接省略. eslint: [`react/jsx-boolean-value`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md)
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
<Foo
|
||||||
|
hidden={true}
|
||||||
|
/>
|
||||||
|
|
||||||
|
// good
|
||||||
|
<Foo
|
||||||
|
hidden
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
- `<img>` 标签总是添加 `alt` 属性. 如果图片以presentation(感觉是以类似PPT方式显示?)方式显示,`alt` 可为空, 或者`<img>` 要包含`role="presentation"`. eslint: [`jsx-a11y/img-has-alt`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-has-alt.md)
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
<img src="hello.jpg" />
|
||||||
|
|
||||||
|
// good
|
||||||
|
<img src="hello.jpg" alt="Me waving hello" />
|
||||||
|
|
||||||
|
// good
|
||||||
|
<img src="hello.jpg" alt="" />
|
||||||
|
|
||||||
|
// good
|
||||||
|
<img src="hello.jpg" role="presentation" />
|
||||||
|
```
|
||||||
|
|
||||||
|
- 不要在 `alt` 值里使用如 "image", "photo", or "picture"包括图片含义这样的词, 中文也一样. eslint: [`jsx-a11y/img-redundant-alt`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-redundant-alt.md)
|
||||||
|
|
||||||
|
> 为什么? 屏幕助读器已经把 `img` 标签标注为图片了, 所以没有必要再在 `alt` 里说明了.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
<img src="hello.jpg" alt="Picture of me waving hello" />
|
||||||
|
|
||||||
|
// good
|
||||||
|
<img src="hello.jpg" alt="Me waving hello" />
|
||||||
|
```
|
||||||
|
|
||||||
|
- 使用有效正确的 aria `role`属性值 [ARIA roles](https://www.w3.org/TR/wai-aria/roles#role_definitions). eslint: [`jsx-a11y/aria-role`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-role.md)
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad - not an ARIA role
|
||||||
|
<div role="datepicker" />
|
||||||
|
|
||||||
|
// bad - abstract ARIA role
|
||||||
|
<div role="range" />
|
||||||
|
|
||||||
|
// good
|
||||||
|
<div role="button" />
|
||||||
|
```
|
||||||
|
|
||||||
|
- 不要在标签上使用 `accessKey` 属性. eslint: [`jsx-a11y/no-access-key`](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-access-key.md)
|
||||||
|
|
||||||
|
> 为什么? 屏幕助读器在键盘快捷键与键盘命令时造成的不统一性会导致阅读性更加复杂.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
<div accessKey="h" />
|
||||||
|
|
||||||
|
// good
|
||||||
|
<div />
|
||||||
|
```
|
||||||
|
- 避免使用数组的index来作为属性`key`的值,推荐使用唯一ID. ([为什么?](https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318))
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
{todos.map((todo, index) =>
|
||||||
|
<Todo
|
||||||
|
{...todo}
|
||||||
|
key={index}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
// good
|
||||||
|
{todos.map(todo => (
|
||||||
|
<Todo
|
||||||
|
{...todo}
|
||||||
|
key={todo.id}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Refs
|
||||||
|
|
||||||
|
- 总是在Refs里使用回调函数. eslint: [`react/no-string-refs`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md)
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
<Foo
|
||||||
|
ref="myRef"
|
||||||
|
/>
|
||||||
|
|
||||||
|
// good
|
||||||
|
<Foo
|
||||||
|
ref={ref => { this.myRef = ref; }}
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Parentheses 括号
|
||||||
|
|
||||||
|
- 将多行的JSX标签写在 `()`里. eslint: [`react/wrap-multilines`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/wrap-multilines.md)
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
render() {
|
||||||
|
return <MyComponent className="long body" foo="bar">
|
||||||
|
<MyChild />
|
||||||
|
</MyComponent>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// good
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<MyComponent className="long body" foo="bar">
|
||||||
|
<MyChild />
|
||||||
|
</MyComponent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// good, 单行可以不需要
|
||||||
|
render() {
|
||||||
|
const body = <div>hello</div>;
|
||||||
|
return <MyComponent>{body}</MyComponent>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tags 标签
|
||||||
|
|
||||||
|
- 对于没有子元素的标签来说总是自己关闭标签. eslint: [`react/self-closing-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md)
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
<Foo className="stuff"></Foo>
|
||||||
|
|
||||||
|
// good
|
||||||
|
<Foo className="stuff" />
|
||||||
|
```
|
||||||
|
|
||||||
|
- 如果模块有多行的属性, 关闭标签时新建一行. eslint: [`react/jsx-closing-bracket-location`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md)
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
<Foo
|
||||||
|
bar="bar"
|
||||||
|
baz="baz" />
|
||||||
|
|
||||||
|
// good
|
||||||
|
<Foo
|
||||||
|
bar="bar"
|
||||||
|
baz="baz"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Methods 函数
|
||||||
|
|
||||||
|
- 使用箭头函数来获取本地变量.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
function ItemList(props) {
|
||||||
|
return (
|
||||||
|
<ul>
|
||||||
|
{props.items.map((item, index) => (
|
||||||
|
<Item
|
||||||
|
key={item.key}
|
||||||
|
onClick={() => doSomethingWith(item.name, index)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 当在 `render()` 里使用事件处理方法时,提前在构造函数里把 `this` 绑定上去. eslint: [`react/jsx-no-bind`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md)
|
||||||
|
|
||||||
|
> 为什么? 在每次 `render` 过程中, 再调用 `bind` 都会新建一个新的函数,浪费资源.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
class extends React.Component {
|
||||||
|
onClickDiv() {
|
||||||
|
// do stuff
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <div onClick={this.onClickDiv.bind(this)} />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// good
|
||||||
|
class extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.onClickDiv = this.onClickDiv.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickDiv() {
|
||||||
|
// do stuff
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <div onClick={this.onClickDiv} />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 在React模块中,不要给所谓的私有函数添加 `_` 前缀,本质上它并不是私有的.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
React.createClass({
|
||||||
|
_onClickSubmit() {
|
||||||
|
// do stuff
|
||||||
|
},
|
||||||
|
|
||||||
|
// other stuff
|
||||||
|
});
|
||||||
|
|
||||||
|
// good
|
||||||
|
class extends React.Component {
|
||||||
|
onClickSubmit() {
|
||||||
|
// do stuff
|
||||||
|
}
|
||||||
|
|
||||||
|
// other stuff
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- 在 `render` 方法中总是确保 `return` 返回值. eslint: [`require-render-return`](https://github.com/yannickcr/eslint-plugin-react/pull/502)
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
// bad
|
||||||
|
render() {
|
||||||
|
(<div />);
|
||||||
|
}
|
||||||
|
|
||||||
|
// good
|
||||||
|
render() {
|
||||||
|
return (<div />);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ordering React 模块生命周期
|
||||||
|
|
||||||
|
- `class extends React.Component` 的生命周期函数:
|
||||||
|
|
||||||
|
1. 可选的 `static` 方法
|
||||||
|
1. `constructor` 构造函数
|
||||||
|
1. `getChildContext` 获取子元素内容
|
||||||
|
1. `componentWillMount` 模块渲染前
|
||||||
|
1. `componentDidMount` 模块渲染后
|
||||||
|
1. `componentWillReceiveProps` 模块将接受新的数据
|
||||||
|
1. `shouldComponentUpdate` 判断模块需不需要重新渲染
|
||||||
|
1. `componentWillUpdate` 上面的方法返回 `true`, 模块将重新渲染
|
||||||
|
1. `componentDidUpdate` 模块渲染结束
|
||||||
|
1. `componentWillUnmount` 模块将从DOM中清除, 做一些清理任务
|
||||||
|
1. *点击回调或者事件处理器* 如 `onClickSubmit()` 或 `onChangeDescription()`
|
||||||
|
1. *`render` 里的 getter 方法* 如 `getSelectReason()` 或 `getFooterContent()`
|
||||||
|
1. *可选的 render 方法* 如 `renderNavigation()` 或 `renderProfilePicture()`
|
||||||
|
1. `render` render() 方法
|
||||||
|
|
||||||
|
- 如何定义 `propTypes`, `defaultProps`, `contextTypes`, 等等其他属性...
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import React, { PropTypes } from 'react';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
id: PropTypes.number.isRequired,
|
||||||
|
url: PropTypes.string.isRequired,
|
||||||
|
text: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultProps = {
|
||||||
|
text: 'Hello World',
|
||||||
|
};
|
||||||
|
|
||||||
|
class Link extends React.Component {
|
||||||
|
static methodsAreOk() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <a href={this.props.url} data-id={this.props.id}>{this.props.text}</a>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Link.propTypes = propTypes;
|
||||||
|
Link.defaultProps = defaultProps;
|
||||||
|
|
||||||
|
export default Link;
|
||||||
|
```
|
||||||
|
|
||||||
|
- `React.createClass` 的生命周期函数,与使用class稍有不同: eslint: [`react/sort-comp`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md)
|
||||||
|
|
||||||
|
1. `displayName` 设定模块名称
|
||||||
|
1. `propTypes` 设置属性的类型
|
||||||
|
1. `contextTypes` 设置上下文类型
|
||||||
|
1. `childContextTypes` 设置子元素上下文类型
|
||||||
|
1. `mixins` 添加一些mixins
|
||||||
|
1. `statics`
|
||||||
|
1. `defaultProps` 设置默认的属性值
|
||||||
|
1. `getDefaultProps` 获取默认属性值
|
||||||
|
1. `getInitialState` 或者初始状态
|
||||||
|
1. `getChildContext`
|
||||||
|
1. `componentWillMount`
|
||||||
|
1. `componentDidMount`
|
||||||
|
1. `componentWillReceiveProps`
|
||||||
|
1. `shouldComponentUpdate`
|
||||||
|
1. `componentWillUpdate`
|
||||||
|
1. `componentDidUpdate`
|
||||||
|
1. `componentWillUnmount`
|
||||||
|
1. *clickHandlers or eventHandlers* like `onClickSubmit()` or `onChangeDescription()`
|
||||||
|
1. *getter methods for `render`* like `getSelectReason()` or `getFooterContent()`
|
||||||
|
1. *Optional render methods* like `renderNavigation()` or `renderProfilePicture()`
|
||||||
|
1. `render`
|
||||||
|
|
||||||
|
## isMounted
|
||||||
|
|
||||||
|
- 不要再使用 `isMounted`. eslint: [`react/no-is-mounted`](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md)
|
||||||
|
|
||||||
|
> 为什么? [`isMounted` 反人类设计模式:()][anti-pattern], 在 ES6 classes 中无法使用, 官方将在未来的版本里删除此方法.
|
||||||
|
|
||||||
|
[anti-pattern]: https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html
|
||||||
|
|
||||||
|
**[⬆ 回到顶部](#内容目录)**
|
Loading…
Reference in New Issue