See the Pen react-tabs by Wang Chao (@charleyw) on CodePen.css
既然用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
按照以前的想法,咱們用Tab
定義了不少個標籤頁,咱們須要根據這些定義生成標籤頁的標題欄和內容。code
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>)
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
這裏要出現React最重要的概念了state
,state
是一個Javascript的Object,它是用來表示組件的當前狀態的,若是用TabsControl
舉例的話,它的state
能夠是當前處於激活狀態的標籤頁編號(固然,若是你想的話也能夠保存標籤頁的內容)。
React提供了一個方法setState()
讓你能夠改變state
的值。每次調用setState()
都會觸發組件的render()
,也就是說會把組件所表明的DOM更新到state
所表明的狀態。get
因此實現切換的關鍵以下:it
state
保存當前處於激活狀態的標籤頁的編號
點擊標題的時候調用setState()
更新激活的標籤頁編號
render()
的時候,在遍歷this.props.children
的時候把編號與state
中編號一致的元素標記爲active
用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()
方法重繪標籤頁。
上面一系列的操做最終的結果都須要用render()
來反應出來,因此關鍵點是如何在render()
中使用state
來動態生成DOM.
實現能夠滑動的標籤頁