阅读65 返回首页    go 京东网上商城


通过 JSX Control Statements 编写 JSX

通过 JSX Control Statements 编写 JSX

一、前言

一些开发者,特别是有使用过「模板技术」的开发者(例如 Handlebars),刚开始尝试使用 React 编写应用时,可能会惊讶的发现,JSX 竟然没有内建支持类似其它模板引擎似的任何结构控制语句或指令。但这就是 JSX,它就是这么设计的,JSX 不是传统的模板,也不需要某个模板引擎去解析。大体上,可以将 JSX 看成普通 JavaScript 表达式的语法糖。

下边的的代码是一个「普通的 JavaScript 代码示例」

render () {
  return (if(true){
    ...
  }else{
    ...
  });
}

如上代码不合法的,同样,下边的 jsx 代码也是不合法的

render () {
  return (<div>
  {if(true) <span>1</span> else <span>2</span> }
  </div>);
}

因为,JavaScript 不能在一个「表达式」中嵌入「控制语句」。

二、能做什么?

JSX-Control-Statements 为 JSX 增加了基本的结构控制语句,比如条件和循环控制语句。通过将插件将「组件风格」的控制语句最终转换为普通 JS 代码,例如:

<If condition={condition()}>Hello World!</If>

将会转换为

condition() ? 'Hello World!' : null

三、实现原理及说明

这看起来,似乎很容易实现,通过一系列表组件好像就能实现,但事实上这在 React 中这是不可行的,如果用「组件」的方式实现,类似如下代码

<ul>
  <ForComponent each="item" index="index" of={list}>
     <li key={index}>{item.title}</li>
  </ForComponent>
</ul>

组件的方式实现上边的代码,将会抛出来一个错误 Cannot read property 'title' of undefined

因为 React 在执行到 ForComponent 时就是会执行它的 children ,想达到目的,需要延后执行 FormComponent 的 children,那么只能用一个 function 包裹,并在这个函数中返回 jsx 表达式,但这将比直接写 map 方法还麻烦。

所以,JSX Control Statements 是一个 Babel 插件,采取了在「编译阶段」将「控制标签」转换为「普通的 JavaScript 表达式」的方案,最终编译结果和原来的写法没有什么不同。

四、安装

需要先行安装好 Babel,之后通过 npm 安装 jsx-control-statements

npm install --save-dev jsx-control-statements

还需要在 .babelrc 中配置插件,如下

{
  ...
  "plugins": ["jsx-control-statements"]
}

五、核心语法

If 标签

用来表示最简单的条件判断逻辑

// 简单示例
<If condition={ true }>
  <span>IfBlock</span>
</If>

// 包括多个子元素及表达式
<If condition={ true }>
  one { "two" }
  <span>three</span>
  <span>four</span>
</If>

<If>

if 的 body 部分只有在 condition 为 true 才会渲染

属性名 类型 必须
condition boolean

<Else /> (deprecated)

Eles 已废弃,不推荐使用,它会破坏 JSX/XML 的语法,并且影响自动格式化。

转换

If 标签将会预编译为「三元表达式」

// 转换前
<If condition={ test }>
  <span>Truth</span>
</If>

// 转换后
{ test ? <span>Truth</span> : null }

Choose 标签

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>

Choose 的子元素只允许出现 WhenOtherwise,其中最少需要有一个 When,而 Otherwise 是可选的

<When>

<If> 类似

属性名 类型 必须
condition boolean

<Otherwise>

没有任何一个 When 满足条件时,将会渲染 Otherwise

转换

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> }

For 标签

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 循环「索引」变量名

注意,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 标签

用于将值赋给局部变量

// 简单用法
<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 将值赋给指定名称的局部变量

注意,定义的「变量」仅在 With 块中可用。

转换

<With> 将会转换为一个「匿名的立即执行函数」

// 转换前
<With foo={ 47 }>
  <span>{ foo }</span>
</With>


// 转换后
{
  (function(foo) {
    return <span>{ foo }</span>
  }).call(this, 47)
}

六、对比普通 JS/JSX 写法的对比

带来的好处

  • 更直观、对于习惯于模板语法的开发人员或设计人员,更接近于传统模板写法
  • 减少 JS/JSX 相互隔断导致的代码「支离破碎」
  • 更好的可读性和整洁,不过这取决于你的个人喜好。

一点小问题

  • 多了一步编译,会多用一点点构建时间
  • 依赖 Bable 6,并需要配置一下 .babelrc

七、如何进行语法检查?

ESLint

所有结构控制标签都是通过 Babel 插件进行转义的, 不需要 require or import,所有在进行「语法检查」时,将会出现「变量未定义」的警告或错误。

但是,有一个 ESlint 插件可处理这个问题
ESLint plugin for JSX-Control-Statements

-- end --

最后更新:2017-08-18 10:32:25

  上一篇:go  外贸仿牌抗投诉主机
  下一篇:go  深入浅出JS动画