一、前言
@H_
403_2@一些开发者,特别是有使用过「模板技术」的开发者(例如 Handlebars),刚开始尝试使用 React 编写应用时,可能会惊讶的发现,JSX 竟然没有内建
支持类似其它模板引擎似的任何结构控制语句或指令。但这就是 JSX,它就是这么设计的,JSX 不是传统的模板,也不需要某个模板引擎去解析。大体上,可以将 JSX 看成普通 JavaScript 表达式的语法糖。
@H_
403_2@下边的的
代码是一个「普通的 JavaScript
代码示例」
render () {
return (if(true){
...
}else{
...
});
}
@H_
403_2@如上
代码不合法的,同样,下边的 jsx
代码也是不合法的
render () {
return (<div>
{if(true) <span>1</span> else <span>2</span> }
</div>);
}
@H_
403_2@因为,JavaScript 不能在一个「表达式」中嵌入「控制语句」。
二、能做什么?
@H_
403_2@
JSX-Control-Statements 为 JSX
增加了基本的结构控制语句,比如条件和循环控制语句。通过将
插件将「组件风格」的控制语句最终转换为普通 JS
代码,例如:
<If condition={condition()}>Hello World!</If>
@H_
403_2@将会转换为
condition() ? 'Hello World!' : null
三、实现原理及说明
@H_
403_2@这看起来,似乎很容易实现,通过一系列表组件好像就能实现,但事实上这在 React 中这是不可行的,如果用「组件」的方式实现,类似如下
代码
<ul>
<ForComponent each="item" index="index" of={list}>
<li key={index}>{item.title}</li>
</ForComponent>
</ul>
@H_
403_2@组件的方式实现上边的
代码,将会抛出来一个
错误 Cannot read property 'title' of undefined
@H_
403_2@因为 React 在执行到 ForComponent 时就是会执行它的 children ,想达到目的,需要延
后执行 FormComponent 的 children,那么只能用一个 function 包裹,并在这个
函数中返回 jsx 表达式,但这将比直接写 map
方法还麻烦。
@H_
403_2@所以,
JSX Control Statements
是一个 Babel
插件,采取了在「编译阶段」将「控制
标签」转换为「普通的 JavaScript 表达式」的方案,最终编译结果和原来的写法没有什么不同。
四、安装
@H_
403_2@需要先行安装好 Babel,之后通过 npm 安装
jsx-control-statements
npm install --save-dev jsx-control-statements
@H_
403_2@还需要在
.babelrc
中配置
插件,如下
{
...
"plugins": ["jsx-control-statements"]
}
五、核心语法
@H_
403_2@用来表示最简单的
条件判断逻辑
// 简单示例
<If condition={ true }>
<span>IfBlock</span>
</If>
// 包括多个子元素及表达式
<If condition={ true }>
one { "two" }
<span>three</span>
<span>four</span>
</If>
<If>
@H_
403_2@if 的 body 部分只有在 condition 为 true 才会渲染
属性名 |
类型 |
必须 |
condition |
boolean |
是 |
<Else /> (deprecated)
@H_
403_2@Eles 已废弃,不推荐使用,它会破坏 JSX/XML 的语法,并且影响
自动格式化。
转换
@H_
403_2@If
标签将会预编译为「三元表达式」
// 转换前
<If condition={ test }>
<span>Truth</span>
</If>
// 转换后
{ test ? <span>Truth</span> : null }
Choose 标签
@H_
403_2@Choose 是比 If 更复杂分支结构写法
<Choose>
<When condition={ test1 }>
<span>IfBlock</span>
</When>
<When condition={ test2 }>
<span>ElseIfBlock</span>
<span>Another ElseIfBlock</span>
<span>...</span>
</When>
<Otherwise>
<span>ElseBlock</span>
</Otherwise>
</Choose>
// default block is optional; minimal example:
<Choose>
<When condition={true}>
<span>IfBlock</span>
</When>
</Choose>
<Choose>
@H_
403_2@Choose 的子元素只允许出现
When
和
Otherwise
,其中最少需要有一个
When
,而
Otherwise
是可选的
<When>
@H_
403_2@和
<If>
类似
属性名 |
类型 |
必须 |
condition |
boolean |
是 |
<Otherwise>
@H_
403_2@没有任何一个
When
满足条件时,将会渲染
Otherwise
转换
@H_
403_2@Choose
标签同样将会预编译为「三元表达式」
// 转换前
<Choose>
<When condition={ test1 }>
<span>IfBlock1</span>
</When>
<When condition={ test2 }>
<span>IfBlock2</span>
</When>
<Otherwise>
<span>ElseBlock</span>
</Otherwise>
</Choose>
// 转换后
{ test1 ? <span>IfBlock1</span> : test2 ? <span>IfBlock2</span> : <span>ElseBlock</span> }
@H_
403_2@
For
的命名用
方法,如下
// 注意,需要指定 key 属性
<For each="item" of={ this.props.items }>
<span key={ item.id }>{ item.title }</span>
</For>
<For each="item" index="idx" of={ [1,2,3] }>
<span key={ idx }>{ item }</span>
<span key={ idx + '_2' }>Static Text</span>
</For>
属性名 |
类型 |
必须 |
说明 |
of |
Array/collection |
是 |
列表或包含 map 方法的集合 |
each |
string |
|
循环「项」变量名 |
index |
string |
|
循环「索引」变量名 |
@H_
403_2@注意,
For
不能作为根元素
转换
// 转换前
<For each="item" index="index" of={ items )}>
<span key={ item.id }>{ index }. { item.title }</span>
</For>
// 转换前
{
items.map( function(item,index) {
<span key={ item.id }>{ index }. { item.title }</span>
})
}
With 标签
@H_
403_2@用于将值赋给局部变量
// 简单用法
<With foo={ 47 } bar={ 'test' }>
<span>{ foo }</span>
<span>{ bar }</span>
</With>
// 嵌套使用
<With foo={ 47 }>
<With bar={ 'test' }>
<span>{ foo }</span>
<span>{ bar }</span>
</With>
</With>
属性名 |
类型 |
必须 |
说明 |
any |
any |
|
将值赋给指定名称的局部变量 |
@H_
403_2@注意,定义的「变量」仅在 With 块中可用。
转换
@H_
403_2@
<With>
将会转换为一个「匿名的立即执行
函数」
// 转换前
<With foo={ 47 }>
<span>{ foo }</span>
</With>
// 转换后
{
(function(foo) {
return <span>{ foo }</span>
}).call(this,47)
}
六、对比普通 JS/JSX 写法的对比
带来的好处
- @H_403_2@更直观、对于习惯于模板语法的开发人员或设计人员,更接近于传统模板写法
- @H_403_2@减少 JS/JSX 相互隔断导致的代码「支离破碎」
- @H_403_2@更好的可读性和整洁,不过这取决于你的个人喜好。
一点小问题
- @H_403_2@多了一步编译,会多用一点点构建时间
- @H_403_2@依赖 Bable 6,并需要配置一下 .babelrc
七、如何进行语法检查?
ESLint
@H_
403_2@所有结构控制
标签都是通过 Babel
插件进行转义的,不需要
require
or
import
,所有在进行「语法检查」时,将会出现「变量未定义」的警告或
错误。
@H_
403_2@但是,有一个 ESlint
插件可处理这个问题
ESLint plugin for JSX-Control-Statements
@H_
403_2@-- end --