这两天学习react,撸了一遍文档后开始自己动手写点东西。
正好从朋友那得到灵感,写一个小例子。
这个东西是这样的,就是点击的这个节点就往它里面添加一个child。
于是乎!我想到的就是用自调函数,递归的思想来实现。
看一下他啥样:
解释一下:
~点击【添加根节点】按钮的时候就添加一个父id为空的节点
~点击每一个节点的时候就在它的内部添加一个child
这里为了方便,我的state就写的固定的 = 。=!(强行解释一波:主要锻炼思想),如下:
constructor(props){
super(props);
this.state={
num:1,//用来记录新添加的id
true_tree:[
{name:"本id:1;父id:",id:1,pid:"",child:[]}
]
};
this.addTree=this.addTree.bind(this);
}
页面上的渲染都是根据state里true_tree来决定的,所以,先看一下我是如何渲染的:
show(item){//用来根据true_tree里面的每一个child,循环出每一个子节点,传过来的参数item即为上一层的child
let all = [];//创建一个容器,吧所有层的child都存在这里面一并返回
item.forEach((items,index) => {//因为传过来的child是一个数组,所以需要遍历
all.push(
<div key={items.id} onClick={this.addTree.bind(this,items)}>
{items.name}
{items.child.length>0?this.show(items.child):""}
</div>
);
//递归渲染,如果有child就再执行一遍show方法,渲染出所有child
})
return all;//将所有内容返回输出
}
可以看到,我对渲染出来的div都绑定了一个事件“addTree”,这个方法就是往state中的true_tree中添加节点信息的方法,来看一下:
addTree(item,e){//直接往树里面添加
e.stopPropagation();//防止事件冒泡,必须加上,不加就冒泡,会创建出重复id的节点
let true_tree = this.state.true_tree;//获取到当前的树结构
let sum = this.state.num+1;//新加的节点的id值
let newItem={name:"本id:"+sum+";父id:"+(item==="root"?"":item.id),id:sum,pid:item==="root"?"":item.id,child:[]};//新的节点的详细数据
if(item === "root"){//如果点击了的是添加根目录按钮(那个按钮传过来的是"root")
true_tree.push(newItem);//则添加根节点
}else{
(function sort(t){//这是一个递归方法,如果根据pid在当前这层没找到他的父亲id,那么就去下一层找,还没找到就还去下一层
t.forEach((items,index) => {
if(newItem.pid === items.id){
items.child.push(newItem);//如果找到了对应的父亲,就在这个父亲的child里面添加这个子节点
}else{
sort(items.child);//如果没找到调用本身去下一层找
}
})
})(true_tree);//先从最高层开始根据pid寻找父亲id,所以穿true_tree
}
this.setState({//整个addTree方法结束,更新state
num : sum,
true_tree:true_tree
})
}
当然,一个组件少不了render,一家人就是要整整齐齐的,所以就贴出来吧~:
render(){
return(
<div>
<button onClick={this.addTree.bind(this,"root")}>添加根节点</button>
{this.show(this.state.true_tree)}
</div>
)
}
就这样,这个功能就实现了,其实就是一个用来控制数据的方法(addTree),一个用来控制渲染的方法(show)就完事了。
(当然,想让它变成一个可直接用的组件还需要修改,我发这一版的原因在于他还可以改成很多种组件,根据遇到的需求再改就可以了)