国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

javascript如何用遞歸寫一個簡單的樹形結構示例

2019-11-19 15:32:35
字體:
來源:轉載
供稿:網友

現在有一個數據,需要你渲染出對應的列表出來:

var data = [ {"id":1}, {"id":2}, {"id":3}, {"id":4}, ];var str="<ul>";data.forEach(function(v,i){  str+="<li><span>"+v.id+"</span></li>"})str="</ul>"$(doucment).append(str);

哼,easy!

語罷,又是一道題飛來!

哦,還帶了兒子來當幫手。我一個循環再一個循環,輕松帶走你們

var data2 = [  {"id":1,children:[{"id":"child11"},{"id":"child12"}]},  {"id":2},  {"id":3children:[{"id":"child31"},{"id":"child32"}]},  {"id":4}, ];var str="<ul>";data2.forEach(function(v,i){  if(v.children&&v.children.length>0){    str+="<li><span>"+v.id+"</span>";    str+="<ul>";    v.children.forEach(function(value,index){       str+="<li><span>"+value.id+"</span>";    })    str="</ul>";    str="</li>";  }else{    str+="<li><span>"+v.id+"</span></li>"  } })str="</ul>"$(doucment).append(str);

還有誰?

var json=[    {     name:123,id:1     children:[      {       name:453,id:456,children:[{name:789,id:777,children:[{name:"hahahqqq---qq",id:3232,children:[name:'son',id:"13132123211"]}]}]      },      {       name:"Cessihshis" , id:12121      }     ]    },    {     name:"啊啊啊11", id:12    },   ];

竟然把全家都帶來了,看我循環循環再循環大法。

嗯,不知道他家幾代同堂,我該循環幾次?突然間你感覺遇到對手了。

正納悶著,突然有人拍了一下你的肩膀,兄弟,我這里有一本遞歸秘籍,我看你骨骼驚奇,是個練武奇才,10塊錢賣你了。

 function render(treeJson){    if(!Array.isArray(treeJson)||treeJson.length<=0){return ""}    var ul=$("<ul>");  treeJson.forEach(function(item,i){      var li=$("<li><span class='treeName'>"+item.name+"</span></li>");   if(Array.isArray(item.children)&&item.children.length>0){    li.append(render(item.children))   }   ul.append(li);  })  return ul } $(document).append(render(json));

好了不扯了,通過遞歸,無需再判斷數據有多少層級,只有當前數組有children并且長度大于0,函數就會遞歸調用自身,并且返回一個ul。

這樣一來,一顆非常簡陋的樹就生成了,不過通常樹都帶有radio或者checkbox選擇框,而且很多時候都需要對樹的右側進行拓展,比如加一些新增,編輯等按鈕什么的,可以考慮多傳一個對象作為參數。

   var checkbox={    radio:"<label class='myTreeIcon'><input type='radio' name='selectTreeRedio'><span></span></label>",    multi:"<input type='checkbox' name='selectTreeRedio'>"   }   function render(treeJson,option={type:0,expandDom:function(){}}){       if(!Array.isArray(treeJson)||treeJson.length<=0){return ""}       var {type,expandDom}=option;         var ul=$("<ul>");     treeJson.forEach(function(item,i){      var str="";      if(type==1){       str+=checkbox.multi      }else if(type==2){       str+=checkbox.radio      }      var li=$("<li data-id='"+item+"'>"+str+"<span class='treeName'>"+item.name+"</span></li>");      expandDom&&expandDom(li,item);      if(item.children&&item.children.length>0){       li.append(render(item.children,option))      }      ul.append(li);    })    return ul   }   //option使用了一個默認對象,默認為不需要選擇框和不需要拓展, 如果傳入的type為1或者2,則生成checkbox或者radio,由于radio樣式比較丑,用label包起來自己模擬選中的效果;如果傳入拓展參數,則把當前的父級li以及當前的參數傳入,以便進行拓展。   $("#tree").append(render(json,{    type:1,    expandDom:function(el,data){     el.append("<button>編輯</button><button>測試</button><a data-msg='"+JSON.stringify(data)+"'></a>")    }   }))

有時候后臺返回的可能不是拼裝好層級的數組,而是帶有pid標識的所有數組的集合,比如:

var data = [ {"id":2,"name":"第一級1","pid":0}, {"id":3,"name":"第二級1","pid":2}, {"id":5,"name":"第三級1","pid":4}, {"id":100,"name":"第三級2","pid":3}, {"id":6,"name":"第三級2","pid":3}, {"id":601,"name":"第三級2","pid":6}, {"id":602,"name":"第三級2","pid":6}, {"id":603,"name":"第三級2","pid":6}];為了用遞歸來渲染出樹來,這時,就需要我們手動來將層級裝好了:  function arrayToJson(treeArray){  var r = [];  var tmpMap ={};  for (var i=0, l=treeArray.length; i<l; i++) {   // 以每條數據的id作為obj的key值,數據作為value值存入到一個臨時對象里面   tmpMap[treeArray[i]["id"]]= treeArray[i];   }   for (i=0, l=treeArray.length; i<l; i++) {   var key=tmpMap[treeArray[i]["pid"]];      //循環每一條數據的pid,假如這個臨時對象有這個key值,就代表這個key對應的數據有children,需要Push進去   if (key) {    if (!key["children"]){      key["children"] = [];      key["children"].push(treeArray[i]);    }else{     key["children"].push(treeArray[i]);    }       } else {    //如果沒有這個Key值,那就代表沒有父級,直接放在最外層    r.push(treeArray[i]);   }  }  return r  }

現在我們已經實現了將沒有層級結構的數組轉化為帶有層級的數組,那么問題來了,樹形圖還常常會需要帶搜索功能,有沒有辦法把帶層級結構的數組轉化為不帶層級結構的一個數組呢?因為如果不帶層級的話,進行搜索等操作時就非常方便,一個filter基本就可以搞定了。

  var jsonToArray=function (nodes) {   var r=[];   if (Array.isArray(nodes)) {    for (var i=0, l=nodes.length; i<l; i++) {     r.push(nodes[i]);     if (Array.isArray(nodes[i]["children"])&&nodes[i]["children"].length>0)      //將children遞歸的push到最外層的數組r里面      r = r.concat(jsonToArray(nodes[i]["children"]));       delete nodes[i]["children"]    }   }    return r;  }

這樣,不管后臺返回什么格式給我們,我們都可以自由的互轉了,不管是帶層級的轉不帶層級的,還是把不帶層級的轉化為帶有層級的,都只需要調用一個函數就可以輕松解決。

不過這里有一個隱患,就是由于對象的引用關系,操作后雖然返回了我們需要東西,但是會改變原來的數據。

為了不影響到原來的數據,我們需要復制一份數據,需要進行一次深拷貝。

為什么是深拷貝而不是淺拷貝?因為淺拷貝只會復制最外面的一層,假入某一個key值里面又是一個對象,那對復制后的對象的這個key的值進行操作通用會影響到原來的對象。淺拷貝的方法有很多,ES6的assign,jq第一個參數不為true的 $.extend(),數組的slice(0),還有很多很多。

對于標準的json格式的對象,可以用JSON.parse(JSON.stringify(obj))來實現。當然,本文寫的是遞歸,所以還是來手寫一個

function deepCopy(obj){  var object;  if(Object.prototype.toString.call(obj)=="[object Array]"){     object=[];   for(var i=0;i<obj.length;i++){    object.push(deepCopy(obj[i]))   }     return object  }  if(Object.prototype.toString.call(obj)=="[object Object]"){     object={};   for(var p in obj){    object[p]=obj[p]   }     return object  } }

其實有點類似于淺拷貝,淺拷貝會復制一層,那么我們判斷某個值是對象,通過遞歸再來一次(好比飲料中獎再來一瓶一樣,如果中獎了,就遞歸再來一瓶,又中獎就又遞歸再來一瓶,直到不再中獎),也就是說我們通過無盡的淺拷貝來達到復制一個完全的新的對象的效果。

這樣,對樹結構操作時,只需要傳入深拷貝后新對象,就不會影響原來的對象了;

jsonToArray(deepCopy(data));

亦或是

arrayToJson(deepCopy(data)):

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 曲松县| 海淀区| 渭南市| 大丰市| 当雄县| 华阴市| 临洮县| 尼木县| 兴义市| 白朗县| 大渡口区| 宜兰县| 尚义县| 长顺县| 昌乐县| 乌兰察布市| 澄迈县| 招远市| 邹平县| 资溪县| 临泽县| 奉贤区| 闽清县| 萍乡市| 衢州市| 湘潭县| 灵武市| 遂溪县| 旬阳县| 桑日县| 乐平市| 义马市| 泽库县| 深州市| 连江县| 丽水市| 都昌县| 延川县| 建瓯市| 宁城县| 邻水|