实现需求:todolist实现增删改查;javascript
实现思路:react组件划分。由于用的是localstorage封装了数据库各个组件之间数据库不能同步,因此设计组件的思路是在父组件里进行增删改查后的渲染操做(setstate),父组件app下有增删改查操做,所以有四个子层级组件,考虑到刚开始作删除功能的时候对li有操做,因此把对li的操做(删除),ui样式的变更和渲染统一放在了删除todoitem组件里,所以该组件的功能就是对li执行删除操做,和一些事件处理,组件内容应该返回li和和删除按钮,可是li是一个数组,因此须要作一个循环去不停的渲染todoitem,因此设计一个父组件todomain,todomain的功能就是对数据执行map,map里循环渲染todoitem组件,同事把数组传给子组件todoitem,因此todomain应该是从app(app组件有增长组件传递的数据,并把该数组存到了数据库(localDb),因此要获取这个数组进行渲染)继承数据,所以设计思路如图:前端
app.js,首先看底部render的子组件:java
render(){
return (
<Card className="pannel">
<TodoHeader addTodo={this.addTodo.bind(this)} todos={this.state.todos} showAll={this.showAll.bind(this)} />
<TodoQuery ref="query" todos={this.state.todos} queryList={this.queryList.bind(this)} />
<TodoMain todos={this.state.todos} changeTodoState={this.changeTodoState.bind(this)} deleteTodo={this.deleteTodo.bind(this)} reviseTodo={this.reviseTodo.bind(this)}/>
<TodoRevise ref="modal" todos={this.state.todos} closeDialog={this.closeDialog.bind(this)} reviseContent={this.reviseContent.bind(this)}/>
</Card>
)
}
复制代码
接下来看增长的渲染操做addTodo方法node
addTodo(todoItem){
if(!this.db.get('todos')){
this.db.set('todos',[]);
}
this.state.todos.unshift(todoItem);
if(this.state.todos.length != this.db.get('todos').length){
this.db.get('todos').unshift(todoItem);
}
this.db.set('todos',this.db.get('todos'));
this.setState({
todos:this.db.get('todos')
});
message.config({
top:48,
duration:1
});
message.success('增长成功!');
}
复制代码
删除操做deleteTodoreact
deleteTodo(timeId){
let i =0;
for(i=0;i<this.db.get('todos').length;i++){
if(this.db.get('todos')[i].timeId == timeId){
this.db.get('todos').splice(i,1);
}
}
this.state.todos.map((todo,index) => {
console.log(todo);
if(todo.timeId == timeId){
this.state.todos.splice(index,1);
}
});
this.setState({todos:this.state.todos});
this.db.set('todos',this.db.get('todos'));
message.config({
top:48,
duration:1
});
message.success('删除成功!');
}
复制代码
复制代码
复制代码
- queryList(queryArr){
message.config({
top:48,
duration:1
});
if(this.state.todos.length == this.db.get('todos').length && queryArr.length == 0){
message.warning('查询内容不存在');
return;
}
if(queryArr.length == 0){
message.warning('当前list不存在查询内容,已为您转到所有list');
this.setState({
todos:this.db.get('todos')
});
}else{
this.setState({
todos:queryArr
});
}
}
复制代码
###TodoMain组件:jquery
- return (
<ul className="todo-list">
{this.props.todos.map((todo, index) => {
//return <li style={listStyle}>{this.props.todos[index].text}</li>
return <TodoItem key={index} text={todo.text} isDone={todo.isDone} lastReviseTime={todo.lastReviseTime} timeId={todo.timeId} index={index} {...this.props} />
//return <TodoItem key={index} {...todo} index={index} {...this.props}/>
//map对数组进行了遍历,todo表示每个数组元素text,index表明索引,因此让todoitem渲染的过程是一个循环的渲染过程,每次渲染不同,是动态组件渲染
//做为动态组件,须要一个key,每次渲染的时候key不一样,才会显示不一样的渲染,是一个表示的渲染
})}
</ul>
)
复制代码
###TodoItem组件webpack
- export default class TodoItem extends React.Component{
constructor(){
super();
this.state = {
checkAll:false
}
}
// 鼠标移入
handlerMouseOver(){
ReactDom.findDOMNode(this.refs.deleteBtn).style.display = "inline";
ReactDom.findDOMNode(this.refs.changeBtn).style.display = "inline";
}
// 鼠标移出
handlerMouseOut(){
ReactDom.findDOMNode(this.refs.deleteBtn).style.display = "none";
ReactDom.findDOMNode(this.refs.changeBtn).style.display = "none";
}
// 删除当前任务
handlerDelete(){
this.props.deleteTodo(this.props.timeId);
console.log(this.props.timeId);
}
reviseTodo(){
this.props.reviseTodo(this.props.text,this.props.index,this.props.timeId);
}
render(){
let doneStyle = this.props.isDone ? {color: 'red'} : {color: '#57c5f7'};
return (
<li onMouseOver={this.handlerMouseOver.bind(this)} onMouseOut={this.handlerMouseOut.bind(this)} ref='checkList' > <span style={doneStyle} className="listContent">{this.props.text}</span> <Button ref="deleteBtn" onClick={this.handlerDelete.bind(this)} style={{'display': 'none'}} className="fr libtn-height">删除</Button> <Button ref="changeBtn" style={{'display': 'none'}} className="change libtn-height" onClick={this.reviseTodo.bind(this)}>修改</Button> <span className='product-time'>建立时间:{this.props.timeId}</span><span className='revise-time'>最后修改时间:{this.props.lastReviseTime}</span> </li>
)
}
}
复制代码
###TodoRevise组件git
- class TodoRevise extends React.Component {
constructor(){
super();
this.state={
visible: false
};
}
// 绑定键盘回车事件,添加新任务
showModal(todo,index,timeId) {
this.setState({
visible: true,
reviseList: todo,
reviseIndex:index*1+1,
reviseTimeId:timeId
});
}
handleOk() {
let newList = document.getElementById('reviseinput').value;
let lastReviseTime = new Date().getTime();
this.state.reviseList = newList;
this.props.reviseContent(this.state.reviseList,this.state.reviseIndex,this.state.reviseTimeId,lastReviseTime);
}
handleCancel() {
this.props.closeDialog();
}
copyList(){
document.getElementById('reviseinput').value = this.state.reviseList;
}
keyComplete(event){
let lastReviseTime = new Date().getTime();
if(event.keyCode == 13){
let newList = document.getElementById('reviseinput').value;
this.state.reviseList = newList;
this.props.reviseContent(this.state.reviseList,this.state.reviseIndex,this.state.reviseTimeId,lastReviseTime);
}
}
render() {
return (
<div> <Modal title="修改列表内容" visible={this.state.visible} onOk={this.handleOk.bind(this)} onCancel={this.handleCancel.bind(this)}> <div>您正在修改第{this.state.reviseIndex}条,修改内容为<p className="revise_content" onClick={this.copyList.bind(this)}>{this.state.reviseList}</p></div> <p>在下面输入框中对原内容进行修改(支持回车键保存)</p> <Input type="text" id="reviseinput" placeholder="点击蓝色字体将内容复制到输入框" onKeyUp={this.keyComplete.bind(this)}></Input> </Modal> </div>
)
}
}
export default TodoRevise;
复制代码
###总结与思考es6
####react渲染性能优势:github
var ulRoot = ul.render()
document.body.appendChild(ulRoot)
也就是react中:
ReactDOM.render(<App/>,document.getElementById('ulRoot'));
复制代码
来逐层计算子节点,而后把子节点抛到根节点(ulRoot)下。
####react使用