最近遇到用遞歸算法展示樹形結(jié)構(gòu)的需求,前端要展示的效果如下圖所示:
我們的數(shù)據(jù)格式如下,趣钱,這是簡化后的數(shù)據(jù):
[
{
"id": 1,
"level": 1,
"name": "ResourceName:syR",
"parentId": null,
"child": [
{
"id": 2,
"level": 2,
"name": "ResourceName:RjG",
"parentId": 1,
"child": [
{
"id": 3,
"level": 3,
"name": "ResourceName:Gvz",
"parentId": 2,
"child": []
}
]
},
{
"id": 4,
"level": 2,
"name": "ResourceName:R52",
"parentId": 1,
"child": [
{
"id": 5,
"level": 3,
"name": "ResourceName:R36"竞穷,
"parentId": 4,
"child": []
}
]
}
]
}
]
我們調(diào)取后端的接口返回的數(shù)據(jù)層級是不確定的,這種情況下用遞歸算法展示是最好的喇聊。
因?yàn)槲覀兊臄?shù)據(jù)格式是第一級目錄永遠(yuǎn)只有一個芜飘,所以在實(shí)現(xiàn)的時候我是先將第一層數(shù)據(jù)單獨(dú)取出來务豺,當(dāng)然這在實(shí)際應(yīng)用中可以按照自己的需求去實(shí)現(xiàn),render方法代碼如下:
render(){
const {
resourceOfAppInfoList,
}=this.props;
return (
<div className="tab-content height-300 overflow-auto">
<div className="tab-pane fade active in" id="tab-1">
<div className="exampleList m-auto p-t-5 active">
<div className="exampleList m-auto p-t-5 active">
{
resourceOfAppInfoList.map((item)=>{
return(
<div className="row m-0" key={"resourceOfAppInfoList"+item.id}>
<a className="width_20 pull-left text_gray f-s-16 m-t-5 m-r-5" href="javascript:;">
<i className="fa fa-angle-up"></i>
</a>
<div className="pull-left m-r-10">
<div className="row m-0" onClick={()=>this.changeSwitchShow(item.id)} style={{width: '52px', height: '32px', backgroundColor: '#eee',border:'1px solid #eee', borderRadius: '20px',cursor:' pointer'}}>
<div className="pull-right" style={{width: '30px', height: '30px', borderRadius: '50%', background: '#fff'}}></div>
</div>
</div>
<p className="text_gray m-t-5 p-t-1 m-b-0 pull-left">{item.name}</p>
{this.generateMenu(item.child)}
</div>
)
})
}
</div>
</div>
</div>
</div>
);
}
}
其中resourceOfAppInfoList就是我們從后端獲取到的數(shù)據(jù)嗦明,數(shù)據(jù)格式就如上所示笼沥;
generateMenu就是我們的遞歸算法,代碼如下:
/**
* 數(shù)結(jié)構(gòu)展示
* @param menuObj
* @returns {Array}
*/
generateMenu(menuObj) {
let vdom = [];
if (menuObj instanceof Array) {
let list = [];
for (var item of menuObj) {
list.push(this.generateMenu(item));
}
vdom.push(
<div className="exampleBox">
<div className="vertical-box table-valign-middle">
<div className="exampleLine2 vertical-box-column" >
</div>
<div className="exampleLine vertical-box-column">
</div>
<div className="exampleCon vertical-box-column child">
{list}
</div>
</div>
</div>
);
} else {
vdom.push(
<div className="row m-0">
<div className="switcherBox pull-left m-r-10 m-t-15">
<div className="row m-0">
<div className="pull-left m-r-10">
<div className="row m-0" onClick={()=>this.changeSwitchShow(ary.id)} style={{width: '52px', height: '32px', backgroundColor: '#eee',border:'1px solid #eee', borderRadius: '20px',cursor:' pointer'}}>
<div className="pull-right" style={{width: '30px', height: '30px', borderRadius: '50%', background: '#fff'}}></div>
</div>
</div>
<p className="text_gray m-t-5 p-t-1 m-b-0 pull-left">{ary.name}</p>
</div>
</div>
{
menuObj.child.length!==0?
this.generateMenu(menuObj.child)
:null
}
</div>
);
}
return vdom;
}
最原始的一個樹形結(jié)構(gòu)就展示出來娶牌,實(shí)現(xiàn)的過程大概如下:
1.首先將第一級目錄的child傳到遞歸算法中奔浅,此時child是一個array,generateMenu方法中會先進(jìn)入到if判斷诗良,展示子目錄與父級目錄的層級結(jié)構(gòu)
2.在if方法中將child的第一條數(shù)據(jù)作為menuObj參數(shù)汹桦,調(diào)用自己的方法,此時menuObj是一個object對象鉴裹,此時會進(jìn)入到else判斷舞骆,進(jìn)行開關(guān)按鈕和目錄展示,在方法中繼續(xù)把這個object對象的child作為menuObj參數(shù)調(diào)用自己的方法径荔,此時又會先進(jìn)入到if方法督禽,重復(fù)如此
總的來說就是if方法中負(fù)責(zé)展示層級結(jié)構(gòu),else方法負(fù)責(zé)展示開關(guān)按鈕和目錄名稱总处,我們就需要把數(shù)據(jù)傳過去就可以了狈惫,debug調(diào)試的時候可以很清晰的看出數(shù)據(jù)的展示。
實(shí)現(xiàn)來說相對簡單鹦马,但是網(wǎng)上的方法并不多虱岂,當(dāng)然這種遞歸算法也可以進(jìn)行一些數(shù)據(jù)的初始化玖院,比如將數(shù)據(jù)展平菠红,添加一些字段屬性第岖,可以靈活應(yīng)用。
如有問題试溯,歡迎指正C镒摇!遇绞!