閱讀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動畫