用React實現點擊切換的標籤頁

1、首先是Showcase

See the Pen react-tabs by Wang Chao (@charleyw) on CodePen.css

2、如何實現

既然用React寫,那麼它就必然是一個組件,首先考慮你怎麼使用這個組件,也就是這個組件的接口是怎麼樣的。react

<TabsControl>
  <Tab name="red">
    <div className="red"/>
  </Tab>
  <Tab name="blue">
    <div className="blue"/>
  </Tab>
  <Tab name="yellow">
    <div className="yellow"/>
  </Tab>
</TabsControl>

這個TabsControl做爲父組件,它來控制Tab的如何切換,Tab是用來包裹真正要顯示的內容的,它的name屬性是這個標籤頁的名字,會被顯示在標籤頁的標題欄上。this

3、建立基本元素

按照以前的想法,咱們用Tab定義了不少個標籤頁,咱們須要根據這些定義生成標籤頁的標題欄和內容。code

1. 遍歷this.props.children動態生成標題欄

this.props.children是React內建的一個屬性,用來獲取組件的子元素。由於子元素有多是Object或者Array,因此React提供了一些處理children的輔助方法用來遍歷:React.Children.map接口

那麼動態生成標題的代碼多是這樣子的:事件

React.Children.map(this.props.children, (element, index) => {
    return (<div className="tab-title-item">{element.props.name}</div>)

2. 再用一樣方法生成標籤頁內容

React.Children.map(this.props.children, element => {
    return (element)
})

組合起來就是TabsControl的實現:ip

let TabsControl = React.createClass({
  render: function () {
    let that = this;
    let {baseWidth} = this.props;
    let childrenLength = this.props.children.length;
    return (
      <div>
        <nav className="tab-title-items">
          {React.Children.map(this.props.children, (element, index) => {
            return (<div className="tab-title-item">{element.props.name}</div>)
          })}
        </nav>
        <div className="tab-content-items">
          {React.Children.map(this.props.children, element => {
            return (element)
          })}
        </div>
      </div>
    )
  }
});

加上一些css就能看到一個標籤頁的雛形了。element

3、實現標籤頁切換

這裏要出現React最重要的概念了statestate是一個Javascript的Object,它是用來表示組件的當前狀態的,若是用TabsControl舉例的話,它的state能夠是當前處於激活狀態的標籤頁編號(固然,若是你想的話也能夠保存標籤頁的內容)。
React提供了一個方法setState()讓你能夠改變state的值。每次調用setState()都會觸發組件的render(),也就是說會把組件所表明的DOM更新到state所表明的狀態。get

因此實現切換的關鍵以下:it

  1. state保存當前處於激活狀態的標籤頁的編號

  2. 點擊標題的時候調用setState()更新激活的標籤頁編號

  3. render()的時候,在遍歷this.props.children的時候把編號與state中編號一致的元素標記爲active

  4. 用css將非active的元素隱藏起來

因此代碼是這樣的:

let TabsControl = React.createClass({
  getInitialState: function(){
    return {currentIndex: 0}
  },
  
  getTitleItemCssClasses: function(index){
    return index === this.state.currentIndex ? "tab-title-item active" : "tab-title-item";
  },
  
  getContentItemCssClasses: function(index){
    return index === this.state.currentIndex ? "tab-content-item active" : "tab-content-item";
  },
  
  render: function(){
    let that = this;
    let {baseWidth} = this.props;
    let childrenLength = this.props.children.length;
    return (
      <div>
        <nav className="tab-title-items">
          {React.Children.map(this.props.children, (element, index) => {
            return (<div onClick={() => {this.setState({currentIndex: index})}} className={that.getTitleItemCssClasses(index)}>{element.props.name}</div>)
          })}
        </nav>
        <div className="tab-content-items">
          {React.Children.map(this.props.children, (element, index) => {
            return (<div className={that.getContentItemCssClasses(index)}>{element}</div>)
          })}  
        </div>
      </div>
    )
  }
});

getInitialState:是組件的初始化狀態,默認是第一個標籤頁處於激活狀態。
getTitleItemCssClasses:判斷當前標籤和state中保存的標籤編號是否一直,是則標識爲active
getContentItemCssClasses:同上。
onClick={() => {this.setState({currentIndex: index})}}:標籤頁標題綁定了點擊事件,每次點擊都會更新state保存的標籤頁編號,而後觸發render()方法重繪標籤頁。

4、總結

上面一系列的操做最終的結果都須要用render()來反應出來,因此關鍵點是如何在render()中使用state來動態生成DOM.

接下來的改進

實現能夠滑動的標籤頁

相關文章
相關標籤/搜索