<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ## 第十六步:角色(資料)組件 在這一節里我們將為角色創建資料頁面。它和其它組件有些不同,其不同之處在于: 1. 它有一個覆蓋全頁面的背景圖片。 2. 從一個角色頁面導航至另一個角色頁面并不會卸載組件,因此,在`componentDidMount`內部的`getCharacter`?action僅會被調用一次,比如它更新了URL但并不獲取新數據。 ### Component 在app/components目錄新建文件*Character.js*: ~~~ import React from 'react'; import CharacterStore from '../stores/CharacterStore'; import CharacterActions from '../actions/CharacterActions' class Character extends React.Component { constructor(props) { super(props); this.state = CharacterStore.getState(); this.onChange = this.onChange.bind(this); } componentDidMount() { CharacterStore.listen(this.onChange); CharacterActions.getCharacter(this.props.params.id); $('.magnific-popup').magnificPopup({ type: 'image', mainClass: 'mfp-zoom-in', closeOnContentClick: true, midClick: true, zoom: { enabled: true, duration: 300 } }); } componentWillUnmount() { CharacterStore.unlisten(this.onChange); $(document.body).removeClass(); } componentDidUpdate(prevProps) { // Fetch new charachter data when URL path changes if (prevProps.params.id !== this.props.params.id) { CharacterActions.getCharacter(this.props.params.id); } } onChange(state) { this.setState(state); } render() { return ( <div className='container'> <div className='profile-img'> <a className='magnific-popup' href={'https://image.eveonline.com/Character/' + this.state.characterId + '_1024.jpg'}> <img src={'https://image.eveonline.com/Character/' + this.state.characterId + '_256.jpg'} /> </a> </div> <div className='profile-info clearfix'> <h2><strong>{this.state.name}</strong></h2> <h4 className='lead'>Race: <strong>{this.state.race}</strong></h4> <h4 className='lead'>Bloodline: <strong>{this.state.bloodline}</strong></h4> <h4 className='lead'>Gender: <strong>{this.state.gender}</strong></h4> <button className='btn btn-transparent' onClick={CharacterActions.report.bind(this, this.state.characterId)} disabled={this.state.isReported}> {this.state.isReported ? 'Reported' : 'Report Character'} </button> </div> <div className='profile-stats clearfix'> <ul> <li><span className='stats-number'>{this.state.winLossRatio}</span>Winning Percentage</li> <li><span className='stats-number'>{this.state.wins}</span> Wins</li> <li><span className='stats-number'>{this.state.losses}</span> Losses</li> </ul> </div> </div> ); } } Character.contextTypes = { router: React.PropTypes.func.isRequired }; export default Character; ~~~ 在`componentDidMount`里我們將當前Character ID(從URL獲取)傳遞給`getCharacter`?action并且初始化Magnific Popup lightbox插件。 > 注意:我從未成功使用`ref="magnificPopup"`進行插件初始化,這也是我采用代碼中方法的原因。這也許不是最好的辦法,但它能正常工作。 另外你需要注意,角色組件包含一個全頁面背景圖片,并且在`componentWillUnmount`時移除,因為其它組件不包含這樣的背景圖。它又是什么時候添加上去的呢?在store中當成功獲取到角色數據時。 最后值得一提的是在`componentDidUpdate`中發生了什么。如果我們從一個角色頁面跳轉至另一個角色頁面,我們仍然處于角色組件內,它不會被卸載掉。而因為它沒有被卸載,`componentDidMount`不會去獲取新角色數據,所以我們需要在`componentDidUpdate`中獲取新數據,只要我們仍然處于同一個角色組件且URL是不同的,比如從/characters/1807823526跳轉至/characters/467078888。`componentDidUpdate`在組件的生命周期中,每一次組件狀態變化后都會觸發。 ### Actions 在app/actions目錄新建文件*CharacterActions.js*: ~~~ import alt from '../alt'; class CharacterActions { constructor() { this.generateActions( 'reportSuccess', 'reportFail', 'getCharacterSuccess', 'getCharacterFail' ); } getCharacter(characterId) { $.ajax({ url: '/api/characters/' + characterId }) .done((data) => { this.actions.getCharacterSuccess(data); }) .fail((jqXhr) => { this.actions.getCharacterFail(jqXhr); }); } report(characterId) { $.ajax({ type: 'POST', url: '/api/report', data: { characterId: characterId } }) .done(() => { this.actions.reportSuccess(); }) .fail((jqXhr) => { this.actions.reportFail(jqXhr); }); } } export default alt.createActions(CharacterActions); ~~~ ### Store 在app/store目錄新建文件*CharacterStore.js*: ~~~ import {assign, contains} from 'underscore'; import alt from '../alt'; import CharacterActions from '../actions/CharacterActions'; class CharacterStore { constructor() { this.bindActions(CharacterActions); this.characterId = 0; this.name = 'TBD'; this.race = 'TBD'; this.bloodline = 'TBD'; this.gender = 'TBD'; this.wins = 0; this.losses = 0; this.winLossRatio = 0; this.isReported = false; } onGetCharacterSuccess(data) { assign(this, data); $(document.body).attr('class', 'profile ' + this.race.toLowerCase()); let localData = localStorage.getItem('NEF') ? JSON.parse(localStorage.getItem('NEF')) : {}; let reports = localData.reports || []; this.isReported = contains(reports, this.characterId); // If is NaN (from division by zero) then set it to "0" this.winLossRatio = ((this.wins / (this.wins + this.losses) * 100) || 0).toFixed(1); } onGetCharacterFail(jqXhr) { toastr.error(jqXhr.responseJSON.message); } onReportSuccess() { this.isReported = true; let localData = localStorage.getItem('NEF') ? JSON.parse(localStorage.getItem('NEF')) : {}; localData.reports = localData.reports || []; localData.reports.push(this.characterId); localStorage.setItem('NEF', JSON.stringify(localData)); toastr.warning('Character has been reported.'); } onReportFail(jqXhr) { toastr.error(jqXhr.responseJSON.message); } } export default alt.createStore(CharacterStore); ~~~ 這里我們使用了Underscore的兩個輔助函數[`assign`](http://underscorejs.org/#extendOwn)和[`contains`](http://underscorejs.org/#contains),來合并兩個對象并檢查數組是否包含指定值。 > 注意:在我寫本教程時Babel.js還不支持[`Object.assign`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)方法,并且我覺得`contains`比相同功能的`Array.indexOf() > -1`可讀性要好得多。 就像我在前面解釋過的,這個組件在外觀上和其它組件有顯著的不同。添加`profile`類到`<body>`改變了頁面整個外觀和感覺,至于第二個CSS類,可能是`caldari`、`gallente`、`minmatar`、`amarr`其中的一個,將決定使用哪一個背景圖片。我一般會避免與組件`render()`之外的DOM直接交互,但這里為簡單起見還是允許例外一次。最后,在`onGetCharacterSuccess`方法里我們需要檢查角色在之前是否已經被該用戶舉報過。如果舉報過,舉報按鈕將設置為disabled。*因為這個限制很容易被繞過,所以如果你想嚴格對待舉報的話,你可以在服務端執行一個IP檢查。* 如果角色是第一次被舉報,相關信息會被存儲到Local Storage里,因為我們不能在Local Storage存儲對象,所以我們需要先用`JSON.stringify()`轉換一下。 ![](https://box.kancloud.cn/2015-09-14_55f644556ee10.jpg) 最后,打開routes.js并且為`/characters/:id`添加一個新路由。這個路由使用了動態區段`id`來匹配任意有效Character ID,同時,別忘了導入Character組件。 ~~~ import React from 'react'; import {Route} from 'react-router'; import App from './components/App'; import Home from './components/Home'; import AddCharacter from './components/AddCharacter'; import Character from './components/Character'; export default ( <Route handler={App}> <Route path='/' handler={Home} /> <Route path='/add' handler={AddCharacter} /> <Route path='/characters/:id' handler={Character} /> </Route> ); ~~~ 刷新瀏覽器,點擊一個角色,現在你應該能看到新的角色資料頁面。 ![](https://box.kancloud.cn/2015-09-14_55f64455ebce8.jpg) 下一節我們將介紹如何為Top100角色構建CharacterList組件,并且能夠根據性別、種族、血統進行過濾。恥辱墻(Hall of Shame)同樣也是該組件的一部分。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看