千里之行,始于足下,今天完成了基础工作:棋盘、棋子组件,并完成了交替落子功能。是React基本功能的很好示范,代码贴一下。下一步就是多组件的状态管理、共享了。
这里刚开始使用的是全局变量来管理状态,后来发现这是一个不太对路的方法,后来改用了全局的一个状态管理类来统一管理状态、处理状态变化、订阅监听、激活事件,后面的文章会介绍。
一、组件go.js
想出了一个简单的、避免反复修改DOM的办法,将所有棋子组件在初始化都生成,通过状态控制其是否显示、响应点击事件。
var React = require('react'); var ReactDOM = require('react-dom'); require('../../../css/go.css'); //全局变量 window.gGoConfig = new GoConfig(); class GoConfig{ constructor(){ this.index=0; this.black=true; } inc(){ this.index++; this.black=!this.black; console.log(this); } } //围棋桌面 class GoDesk extends React.Component { constructor(props) { super(props); this.state = { refresh: false }; } render() { var self = this; this.state.refresh=false; var pieces = []; for (var i=0; i<19*19; i++){ pieces.push( <GoPiece color={i % 2==0 ? 'white':'black'} id={'go'+(i+1)} key={'go'+(i+1)}/> ); } return <div className="go-desk"> <div className="go-opr"> <GoBtn title="黑走"/> <GoBtn title="白走"/> <GoBtn title="黑子"/> <GoBtn title="白子"/> </div> <div className="go-board"> {pieces} </div> </div>; } } //可以控制单个按钮的状态 class GoBtn extends React.Component{ constructor(props){ super(props); this.state={ active:false,} this.clickHandle=this.clickHandle.bind(this); } clickHandle(event){ this.setState({active:!this.state.active}); console.log(this.state); } //<img src=img/{this.state.png} /> render(){ var className = "btn btn-default btn-sm"; if(this.state.active==true)className = className+" active"; return <button className={className} onClick={this.clickHandle}>{this.props.title}</button>; } } //使用bootstap的按钮组,可以不用控制按钮的状态,较为方便,还没有完全走通 class GoBtns extends React.Component{ constructor(props){ super(props); this.state={}; this.clickHandle=this.clickHandle.bind(this); } clickHandle(idx){ this.setState({index:idx}); } render(){ return <div class="btn-group" data-toggle="buttons"> <label class="btn btn-primary active"><input type="checkBox" autocomplete="off" checked />黑走(pre-checked)</label> <label class="btn btn-primary"><input type="checkBox" autocomplete="off" />白走</label> <label class="btn btn-primary"><input type="checkBox" autocomplete="off" />黑子</label> <label class="btn btn-primary"><input type="checkBox" autocomplete="off" />白子</label> </div>; } } //棋子 class GoPiece extends React.Component{ constructor(props){ super(props); this.state={ showNum:false,num:0,color:props.color,//or w current:false,visibility:'hidden',} //设置this,很重要 this.handleClick=this.handleClick.bind(this); } handleClick(event){ this.setState({ visibility:this.state.visibility=='hidden'?'visible':'hidden',color:window.gGoConfig.black==true?'black':'white',}); //console.log('click,visibility='+this.state.visibility); window.gGoConfig.inc(); } render(){ var className="go-piece go-piece-"+this.state.color; if (this.state.visibility=='hidden') className = className+" go-piece-hidden"; //console.log(className); return <div className={className} id={this.props.id} onClick={this.handleClick}> <span style={{visibility:this.state.visibility}}>{this.state.num=window.gGoConfig.index}</span> </div>;// style={{visibility:this.state.visibility}} } } ReactDOM.render( <GoDesk />,document.getElementById('go-container') );
二、样式文件go.css
.go-desk{ background-image:url(../img/go/bk.png); width:100%; height:100%; padding:20px; } .go-opr{ height:30px; text-align:center; margin-bottom:10px; } .go-board{ width:800px; height:800px; margin:0 auto; background-image:url(../img/go/board.png); background-repeat:no-repeat; padding:20px; } .go-piece{ width:40px; height:40px; float:left; background-image:url(../img/go/piece.png); text-align:center; line-height:40px; vertical-align:middle; font-size:20px; } .go-piece span{ } .go-piece-white{ background-position:-40px 0; color:black; } .go-piece-black{ background-position:0 0; color:white; } .go-piece-hidden{ background-image:none; }
三、效果
四、全部代码 全部代码下载,请看系列文章第一部分,或点击:http://dl.iteye.com/topics/download/536961c7-38a6-38af-b034-c48034f2aa91