這是一個(gè)稍微簡(jiǎn)單些的組件,它唯一的職責(zé)就是顯示兩張圖片并且處理點(diǎn)擊事件,用于告知哪個(gè)角色勝出。
在components目錄下新建文件Home.js:
import React from 'react';
import {Link} from 'react-router';
import HomeStore from '../stores/HomeStore'
import HomeActions from '../actions/HomeActions';
import {first, without, findWhere} from 'underscore';
class Home extends React.Component {
constructor(props) {
super(props);
this.state = HomeStore.getState();
this.onChange = this.onChange.bind(this);
}
componentDidMount() {
HomeStore.listen(this.onChange);
HomeActions.getTwoCharacters();
}
componentWillUnmount() {
HomeStore.unlisten(this.onChange);
}
onChange(state) {
this.setState(state);
}
handleClick(character) {
var winner = character.characterId;
var loser = first(without(this.state.characters, findWhere(this.state.characters, { characterId: winner }))).characterId;
HomeActions.vote(winner, loser);
}
render() {
var characterNodes = this.state.characters.map((character, index) => {
return (
<div key={character.characterId} className={index === 0 ? 'col-xs-6 col-sm-6 col-md-5 col-md-offset-1' : 'col-xs-6 col-sm-6 col-md-5'}>
<div className='thumbnail fadeInUp animated'>
<img onClick={this.handleClick.bind(this, character)} src={'http://image.eveonline.com/Character/' + character.characterId + '_512.jpg'}/>
<div className='caption text-center'>
<ul className='list-inline'>
<li><strong>Race:</strong> {character.race}</li>
<li><strong>Bloodline:</strong> {character.bloodline}</li>
</ul>
<h4>
<Link to={'/characters/' + character.characterId}><strong>{character.name}</strong></Link>
</h4>
</div>
</div>
</div>
);
});
return (
<div className='container'>
<h3 className='text-center'>Click on the portrait. Select your favorite.</h3>
<div className='row'>
{characterNodes}
</div>
</div>
);
}
}
export default Home;
2015年7月27日更新:修復(fù)“Cannot read property ‘characterId’ of undefined”錯(cuò)誤,我更新了在handleClick()
方法里獲取“失敗”的Character ID。它使用_.findWhere
在數(shù)組里查找“獲勝”的角色對(duì)象,然后使用_.without
獲取不包含“獲勝”角色的數(shù)組,因?yàn)閿?shù)組只包含兩個(gè)角色,所以這就是我們需要的,然后使用_.first
獲取數(shù)組第一個(gè)元素,也就是我們需要的對(duì)象。
鑒于角色數(shù)組只有兩個(gè)元素,其實(shí)沒有必要非要使用map方法不可,雖然這也能達(dá)到我們的目的。另一種做法是為characters[0]
和characters[1]
各自創(chuàng)建標(biāo)記。
render() {
return (
<div className='container'>
<h3 className='text-center'>Click on the portrait. Select your favorite.</h3>
<div className='row'>
<div className='col-xs-6 col-sm-6 col-md-5 col-md-offset-1'>
<div className='thumbnail fadeInUp animated'>
<img onClick={this.handleClick.bind(this, characters[0])} src={'http://image.eveonline.com/Character/' + characters[0].characterId + '_512.jpg'}/>
<div className='caption text-center'>
<ul className='list-inline'>
<li><strong>Race:</strong> {characters[0].race}</li>
<li><strong>Bloodline:</strong> {characters[0].bloodline}</li>
</ul>
<h4>
<Link to={'/characters/' + characters[0].characterId}><strong>{characters[0].name}</strong></Link>
</h4>
</div>
</div>
</div>
<div className='col-xs-6 col-sm-6 col-md-5'>
<div className='thumbnail fadeInUp animated'>
<img onClick={this.handleClick.bind(this, characters[1])} src={'http://image.eveonline.com/Character/' + characters[1].characterId + '_512.jpg'}/>
<div className='caption text-center'>
<ul className='list-inline'>
<li><strong>Race:</strong> {characters[1].race}</li>
<li><strong>Bloodline:</strong> {characters[1].bloodline}</li>
</ul>
<h4>
<Link to={'/characters/' + characters[1].characterId}><strong>{characters[1].name}</strong></Link>
</h4>
</div>
</div>
</div>
</div>
</div>
);
}
第一張圖片使用Bootstrap中的col-md-offset-1
位移,所以兩張圖片是完美居中的。
注意我們?cè)邳c(diǎn)擊事件上綁定的不是this.handleClick
,而是this.handleClick.bind(this, character)
。簡(jiǎn)單的傳遞一個(gè)事件對(duì)象是不夠的,它不會(huì)給我們?nèi)魏斡杏玫男畔?,不像文本字段、單選、復(fù)選框元素等。
MSDN文檔中的解釋:
function.bind(thisArg[, arg1[, arg2[, ...]]])
簡(jiǎn)單的來說,因?yàn)槲覀冃枰?code>handleClick方法里引用this.state
,所以需要將this
上下文傳遞進(jìn)去。另外我們還傳遞了被點(diǎn)擊的角色對(duì)象,而不是當(dāng)前的event對(duì)象。
handleClick
方法里的character
參數(shù)代表的是獲勝的角色,因?yàn)樗潜稽c(diǎn)擊的那一個(gè)。因?yàn)槲覀儍H有兩個(gè)角色需要判斷,所以不難分辨誰是輸?shù)哪莻€(gè)。接下來將獲勝和失敗的角色Character ID傳遞給Character ID
action。
在actions目錄下新建HomeActions.js:
import alt from '../alt';
class HomeActions {
constructor() {
this.generateActions(
'getTwoCharactersSuccess',
'getTwoCharactersFail',
'voteFail'
);
}
getTwoCharacters() {
$.ajax({ url: '/api/characters' })
.done(data => {
this.actions.getTwoCharactersSuccess(data);
})
.fail(jqXhr => {
this.actions.getTwoCharactersFail(jqXhr.responseJSON.message);
});
}
vote(winner, loser) {
$.ajax({
type: 'PUT',
url: '/api/characters' ,
data: { winner: winner, loser: loser }
})
.done(() => {
this.actions.getTwoCharacters();
})
.fail((jqXhr) => {
this.actions.voteFail(jqXhr.responseJSON.message);
});
}
}
export default alt.createActions(HomeActions);
這里我們不需要voteSuccess
action,因?yàn)?code>getTwoCharacters已經(jīng)滿足了我們的需求。換句話說,在一次成功的投票之后,我們需要從數(shù)據(jù)庫獲取兩個(gè)新的隨機(jī)角色顯示出來。
在stores目錄下新建文件HomeStore.js:
import alt from '../alt';
import HomeActions from '../actions/HomeActions';
class HomeStore {
constructor() {
this.bindActions(HomeActions);
this.characters = [];
}
onGetTwoCharactersSuccess(data) {
this.characters = data;
}
onGetTwoCharactersFail(errorMessage) {
toastr.error(errorMessage);
}
onVoteFail(errorMessage) {
toastr.error(errorMessage);
}
}
export default alt.createStore(HomeStore);
下一步,讓我們實(shí)現(xiàn)剩下的Express路由,來獲取并更新Home組件中的兩個(gè)角色、獲得總角色數(shù)量等等。
更多建議: