這兩天學習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)就完事了。
(當然,想讓它變成一個可直接用的組件還需要修改,我發這一版的原因在於他還可以改成很多種組件,根據遇到的需求再改就可以了)