React规范
React规范
##**一、基础规范**
1. 统一全部采用 Es6
3. 每个文件只包含的一个 React 组件(联系紧密的组件可以使用「命名空间的形式」)。
4. 始终使用 JSX 语法,不要使用 `React.createElement` 创建 ReactElement,以提高编写速度、可读性、可维护性(没有 JSX 转换的特殊场景例外,如在 `console` 中测试组件)。
##**二、命名规范**
- **扩展名**:使用 .js 作为 React 组件的扩展名;
- **文件名**:使用大驼峰,如 MyComponent.js;
- **组件命名**:组件名称和文件名一致,如 MyComponent.js 里的组件名应该是 MyComponent;一个目录的根组件使用 index.js 命名,以目录名称作为组件名称;
1 // file contents 2 const CheckBox = React.createClass({ 3 // ... 4 }) 5 6 module.exports = CheckBox; 7 8 // in some other file 9 // bad 10 const CheckBox = require('./checkBox'); 11 12 // bad 13 const CheckBox = require('./check_box'); 14 15 // good 16 const CheckBox = require('./CheckBox');
- **引用命名**:React 组件使用大驼峰命名法,HTML 标签、组件实例使用小驼峰命名法;
// bad const Footer = require('./Footer/Footer.js') // bad const Footer = require('./Footer/index.js') // good const Footer = require('./Footer')
- **属性命名**
#
1. React 组件的属性使用**小驼峰命名法**;
2. 使用 `className` 代替 `class` 属性;
3. 使用 `htmlFor` 代替 `for` 属性。
#
- **传递给 HTML 的属性:**
1. 传递给 HTML 元素的自定义属性,需要添加 `data-` 前缀,React 不会渲染非标准属性;
2. [无障碍](http://www.w3.org/WAI/intro/aria)属性 `aria-` 可以正常使用。
- **属性设置**
#
1. 在组件行内设置属性(以便 `propTypes` 校验),不要在外部改变属性的值;
2. 属性较多使用 `{...this.props}` 语法;
3. 重复设置属性值时,前面的值会被后面的覆盖。
var component = <Component />; component.props.foo = x; // bad component.props.bar = y; // also bad // good var component = <Component foo={x} bar={y} />; // good var props = {}; props.foo = x; props.bar = y; var component = <Component {...props} />; var props = { foo: 'default' }; var component = <Component {...props} foo={'override'} />; console.log(component.props.foo); // 'override'
- **属性对齐方式**
#
1. 属性较少时可以行内排列;
2. 属性较多时每行一个属性,闭合标签单独成行
// bad - too long <input type="text" value={this.state.newDinosaurName} onChange={this.inputHandler.bind(this, 'newDinosaurName')} /> // bad - aligning attributes after the tag <input type="text" value={this.state.newDinosaurName} onChange={this.inputHandler.bind(this, 'newDinosaurName')} /> // good <input type="text" value={this.state.newDinosaurName} onChange={this.inputHandler.bind(this, 'newDinosaurName')} /> // if props fit in one line then keep it on the same line <Foo bar="bar" /> // children get indented normally <Foo superLongParam="bar" anotherSuperLongParam="baz" > <Spazz /> </Foo> // bad <Foo bar="bar" baz="baz" /> // good <Foo bar="bar" baz="baz" />
- **带命名空间的组件**
如果一个组件有许多关联子组件,可以以该组件作为命名空间编写、调用子组件。
var MyFormComponent = React.createClass({ ... }); MyFormComponent.Row = React.createClass({ ... }); MyFormComponent.Label = React.createClass({ ... }); MyFormComponent.Input = React.createClass({ ... }); var Form = MyFormComponent; var App = ( );
##**三、组件相关规范**
- **组件声明**
// bad export default React.createClass({ displayName: 'ReservationCard', // stuff goes here }); // good const ReservationCard = React.createClass({ // stuff goes here }); export default ReservationCard;
- **行内迭代**
运算逻辑简单的直接使用行内迭代。
return ( <div> {this.props.data.map(function(data, i) { return (<Component data={data} key={i} />) })} </div> );
- **注释**
组件之间的注释需要用 `{}` 包裹。
var content = ( <Nav> {/* child comment, put {} around */} <Person /* multi line comment */ name={window.isLoggedIn ? window.name : ''} // end of line comment /> </Nav> );
- **引号使用**
1. HTML/JSX 属性使用**双引号** `"`;
2. JS 使用**单引号** `'`;
// bad <Foo bar='bar' /> // good <Foo bar="bar" /> // bad <Foo 20px" }} /> // good <Foo 20px' }} /> // JavaScript Expression const person = <Person name={window.isLoggedIn ? window.name : ''} />; // HTML/JSX const myDivElement = <div className="foo" />; const app = <Nav color="blue" />; const content = ( <Container> {window.isLoggedIn ? <Nav /> : <Login />} </Container> );
- **条件 HTML**
1. 简短的输出在行内直接三元运算符;
#
{this.state.show && 'This is Shown'}
{this.state.on ? 'On' : 'Off'}
2. 较复杂的结构可以在 `.render()` 方法内定义一个以 `Html` 结尾的变量。
var dinosaurHtml = ''; if (this.state.showDinosaurs) { dinosaurHtml = ( <section> <DinosaurTable /> <DinosaurPager /> </section> ); } return ( <div> ... {dinosaurHtml} ... </div> );
- **`()` 使用**
#
1. 多行的 JSX 使用 `()` 包裹,有组件嵌套时使用多行模式;
// bad return (<div><ComponentOne /><ComponentTwo /></div>); // good var multilineJsx = ( <header> <Logo /> <Nav /> </header> ); // good return ( <div> <ComponentOne /> <ComponentTwo /> </div> );
2 单行 JSX 省略 `()`。
var singleLineJsx = <h1>Simple JSX</h1>; // good, when single line render() { const body = <div>hello</div>; return <MyComponent>{body}</MyComponent>; }
- **自闭合标签**
#
1. JSX 中所有标签**必须闭合**;
- 没有子元素的组件使用自闭合语法,自闭合标签 **`/` 前留一个空格**。
// bad <Logo></Logo> <Logo/> // very bad <Foo /> // bad <Foo /> // good <Logo />
- **组件内部代码组织**
#
1. **不要使用下划线前缀**命名 React 组件的方法;
// bad React.createClass({ _onClickSubmit() { // do stuff } // other stuff }); // good React.createClass({ onClickSubmit() { // do stuff } // other stuff });
2. 按照生命周期组顺序织组件的方法、属性;
- 方法(属性)之间空一行;
- `.render()` 方法始终放在最后;
- 自定义方法 React API 方法之后、`.render()` 之前。
// React 组件中按照以下顺序组织代码 React.createClass({ displayName: '', mixins: [], statics: {}, propTypes: {}, getDefaultProps() { // ... }, getInitialState() { // do something }, componentWillMount() { // do something }, componentDidMount() { // do something: add DOM event listener, etc. }, componentWillReceiveProps() { }, shouldComponentUpdate() {}, componentWillUpdate() {}, componentDidUpdate() {}, componentWillUnmount() { // do something: remove DOM event listener. etc. }, // clickHandlers or eventHandlers like onClickSubmit() or onChangeDescription() handleClick() { // ... }, // getter methods for render like getSelectReason() or getFooterContent() // Optional render methods like renderNavigation() or renderProfilePicture() render() { // ... } });
###**三、约定**
**注释**
文件头部注释
/* ------------------------------------------------------------ author : cattleya create:2016-12-30 descreption:recharge相关样式(包含input/label/button) ------------------------------------------------------------ */
注:避免使用多行注释 `/**/`,应使用多个单行注释 `//`
函数注释,可使用块级注释
/* *函数注释 *@ param {string} p1 参数1的说明 *@ param {string} p2 参数2的说明,比较长 *@ return 返回值描述 */ aa() => { alert(); }
**条件(三元)操作符 (?:)**
三元操作符用于替代 if 条件判断语句。
// bad if (val != 0) { return foo(); } else { return bar(); } // good return val ? foo() : bar();
##**四、CSS相关规范**
###**一、代码组织**
**Class 和 ID**
- 使用语义化、通用的命名方式(不能使用汉语拼音);
- 使用连字符 作为 ID、Class 名称界定符,不要驼峰命名法和下划线;
- 避免选择器嵌套层级过多,尽量少于 3 级;
- 避免选择器和 Class、ID 叠加使用;
/* Not recommended */ .red {} .box_green {} .page .header .login #username input {} ul#example {} /* Recommended */ #nav {} .box-video {} #username input {} #example {}
**声明块格式**
- 选择器分组时,保持独立的选择器占用一行;
- 有多个选择器公用同一css代码块时,选择器应以逗号分隔,并换行
- 声明块的左括号 { 前添加一个空格;
- 声明块的右括号 } 应单独成行;
- 声明语句中的 ` : ` 后应添加一个空格;
- 声明语句应以分号 ` ;` 结尾;
- 一般以逗号分隔的属性值,每个逗号后应添加一个空格;
- 对于属性值或颜色参数,省略小数前面的 0 (例如,.5 代替 0.5;-.5px 代替 -0.5px);
- 十六进制值应该全部小写和尽量简写,例如,#fff 代替 #ffffff;
- 避免为 0 值指定单位,例如,用 margin: 0; 代替 margin: 0px;;
/* Not recommended */ .selector, .selector-secondary, .selector[type=text] { padding:15px; margin:0px 0px 15px; background-color:rgba(0, 0, 0, 0.5); box-shadow:0px 1px 2px #CCC,inset 0 1px 0 #FFFFFF } .m-userlist .list { position: relative; height: 100px;overflow: hidden} /* Recommended */ .selector, .selector-secondary, .selector[type="text"] { padding: 15px; margin-bottom: 15px; background-color: rgba(0,0,0,.5); box-shadow: 0 1px 2px #ccc, inset 0 1px 0 #fff; }
**hack**
能不使用hack尽量不要使用,如果必须使用,请将hack加在属性上
如
.head{
*height: 200px;
}
**媒体查询(Media query)的位置**
将媒体查询放在尽可能相关规则的附近。不要将他们打包放在一个单一样式文件中或者放在文档底部。如果你把他们分开了,将来只会被大家遗忘。
.element { ... } .element-avatar { ... } .element-selected { ... } @media (max-width: 768px) { .element { ...} .element-avatar { ... } .element-selected { ... } }
**引号使用**
url() 、属性选择符、属性值使用双引号。 参考[ Is quoting the value of url() really necessary?](http://stackoverflow.com/questions/2168855/is-quoting-the-value-of-url-really-necessary)
/* Not recommended */ html { font-family: 'open sans', arial, sans-serif; } /* Recommended */ html { font-family: "open sans", arial, sans-serif; } .selector[type="text"] { }
**不要使用 @import**
与 <link> 相比,@import 要慢很多,不光增加额外的请求数,还会导致不可预料的问题。
替代办法:
使用多个 元素;
通过 Sass 或 Less 类似的 CSS 预处理器将多个 CSS 文件编译为一个文件;
其他 CSS 文件合并工具;
**注释**
不同模块的内容,在头部、媒体公告添加模块名称等
如果下为头部、媒体公告css
/* 头部模块 ============================================================================*/ # /* 媒体公告模块 ============================================================================*/ .m-userlist { /* 属性声明 */ margin: 0 0 30px; /* 属性名:属性值; */ } /* 左侧部分 */ .m-userlist .list { position: relative; height: 100px; overflow: hidden; } /* 右侧部分 */ .m-userlist .list { position: relative; height: 100px; overflow: hidden; }
###**二、性能优化**
**避免过分重排**
当发生重排的时候,浏览器需要重新计算布局位置与大小,[更多详情](http://www.jianshu.com/p/e305ace24ddf)。
常见的重排元素:
- width
- height
- padding
- margin
- display
- border-width
- position
- top
- left
- right
- bottom
- font-size
- float
- text-align
- overflow-y
- font-weight
- overflow
- font-family
- line-height
- vertical-align
- clear
- white-space
- min-height
**正确使用 Display 的属性**
#
- Display 属性会影响页面的渲染,请合理使用。
- display: inline后不应该再使用 width、height、margin、padding 以及 float;
- display: inline-block 后不应该再使用 float;
- display: block 后不应该再使用 vertical-align;
- display: table-* 后不应该再使用 margin 或者 float;
#
**不滥用 Float**
Float在渲染时计算量比较大,尽量减少使用。
## 五、代码校验工具
- [ESLint](https://www.github.com/eslint/eslint)
- [ESLint React Plugin](https://github.com/yannickcr/eslint-plugin-react)
- 上一篇 »WEB前端规范,一--HTML规范
- 下一篇 »Dojo Javascript 编程规范,转