原理弄明白了,准备开始弄。
可是,笔记本电脑发生了一件很诡异的事件:chrome怎么也打不开开发者工具,热键、右键、菜单都不行。没有console输出的错误的提示,找不到错误代码的位置,只能靠猜,代码很快就写好了,调试、除错花了一个上午的时间也没有搞定。
下午卸载、重新安装chrome,开发者工具好了,很快就把代码调好了。
一个状态管理器、几个组件,代码、逻辑、流程很简单,画个示意图。
一、状态管理器
状态管理器维护组件的全局状态,使用EventEmitter模块注册事件监听器、激活事件。事件管理可以使用node.js带的EventEmitter模块,也可以自己定义一个简单的订阅/发布管理器。
/** * 用于GO的状态管理。管理所有组件的状态,所有组件订阅事件,同步状态 */ var Events = require('events'); class GoStateManager { constructor() { this.current = { index:1,//当前步数 black:false,//是否是黑子 place:false,//是否是布局摆子,如果是,不改变当前步数,布局时摆的棋子上面不显示数字 }; this.eventEmitter = new Events.EventEmitter(); }; //订阅状态变化事件 subCurrentChange(listener) { this.eventEmitter.addListener('currentChange',listener); } //状态变化事件发生,通知监听器 pubCurrentChange(){ this.eventEmitter.emit("currentChange",this.current); } //下一步 next(){ if(this.current.place==true){ } else{ this.current.index++; this.current.black=!this.current.black; this.pubCurrentChange(); } } //设置布局状态 setPlace(bPlace){ this.current.place=bPlace; this.pubCurrentChange(); } //重新开始 restart(){ this.current.index=1; this.current.black=true; this.current.place=false; this.pubCurrentChange(); } } module.exports = new GoStateManager();
二、当前步展示组件及测试按钮组件
var React = require('react'); var ReactDOM = require('react-dom'); var StateManager = require('../../store/main/GoStateManager'); //当前步状态指示器,可以指标当前步数、落子方、是否处理布局状态等信息 class CurrentLabel extends React.Component{ constructor(props){ super(props); //使用全局的状态作为初始状态 this.state={ index:StateManager.current.index,black:StateManager.current.black,place:StateManager.current.place,}; //设置currentChange函数的this this.currentChange=this.currentChange.bind(this); //注册事件监听器 StateManager.subCurrentChange(this.currentChange); } //状态改变事件监听器,调整组件的状态 currentChange(current){ this.setState({ index:current.index,black:current.black,place:current.place,}); } render(){ return <span> <strong>当前步数:</strong>{this.state.index} <strong> 落子方:</strong>{this.state.black==true?'黑方':'白方'} <strong> 是否是布局状态:</strong>{this.state.place==true?'布局':'行棋'} </span>; } } //状态指标器测试按钮:下一步 class CurrentTestBtn_Next extends React.Component{ constructor(props ){ super(props); this.state={} this.clickHandle = this.clickHandle.bind(this); } clickHandle(){ //点击事件,通知状态管理器,下一步 StateManager.next(); } render(){ return <button className="btn btn-primary" onClick={this.clickHandle}>下一步</button>; } } //状态指标器测试按钮:切换布局状态 class CurrentTestBtn_Place extends React.Component{ constructor(props ){ super(props); this.state={} this.clickHandle = this.clickHandle.bind(this); } clickHandle(){ StateManager.setPlace(!StateManager.current.place); } render(){ return <button className="btn btn-primary" onClick={this.clickHandle}>切换布局状态</button>; } } //状态指标器测试按钮:切换布局状态 class CurrentTestBtn_Restart extends React.Component{ constructor(props ){ super(props); this.state={} this.clickHandle = this.clickHandle.bind(this); } clickHandle(){ //点击事件,重新开始 StateManager.restart(); } render(){ return <button className="btn btn-primary" onClick={this.clickHandle}>重新开始</button>; } } ReactDOM.render( <div> <CurrentLabel /><br/> <CurrentTestBtn_Next /> <CurrentTestBtn_Place /> <CurrentTestBtn_Restart /> </div>,document.getElementById('main-container') );
三、执行效果
状态指示组件及三个测试按钮。当点击按钮时,状态指示组件的内容会发生相应的变化。
四、自己定义的发布/订阅实现的简单类,上面代码运行不需要这个类
/** * 自定义的发布定阅实现类 */ class MyEventEmitter { constructor() { this.handlers = { }; }; //增加监听 addListener(eventName,handler) { var self = this; if (!(eventName in self.handlers)){ self.handlers[eventName] = []; } self.handlers[eventName].push(handler); return self; } //删除对应的监听 removeListener(eventName,handler) { var self = this; if (!(eventName in self.handlers)){ return; } var idx=-1; for(var i=0; i<self.handlers[eventName].length; i++){ if(self.handlers[eventName][i]==handler){ idx = i; break; } } if(idx!=-1){ self.handlers[eventName].splice(idx,1); } return self; } emit(eventName){ var self = this; var args = Array.prototype.slice.call(arguments,1); if (!(eventName in self.handlers)){ return; } var idx = self.handlers[eventName].length; while(idx--){ self.handlers[eventName][idx].apply(self,args); } return self; } } module.exports = new MyEventEmitter();