亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

javascript如何用遞歸寫一個簡單的樹形結(jié)構(gòu)示例

 更新時間:2017年09月06日 08:31:04   作者:Runlin  
本篇文章主要介紹了javascript如何用遞歸寫一個簡單的樹形結(jié)構(gòu)示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

現(xiàn)在有一個數(shù)據(jù),需要你渲染出對應(yīng)的列表出來:

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!

語罷,又是一道題飛來!

哦,還帶了兒子來當(dāng)幫手。我一個循環(huán)再一個循環(huán),輕松帶走你們

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
    },
   ];

竟然把全家都帶來了,看我循環(huán)循環(huán)再循環(huán)大法。

嗯,不知道他家?guī)状茫以撗h(huán)幾次?突然間你感覺遇到對手了。

正納悶著,突然有人拍了一下你的肩膀,兄弟,我這里有一本遞歸秘籍,我看你骨骼驚奇,是個練武奇才,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));

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

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

   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使用了一個默認(rèn)對象,默認(rèn)為不需要選擇框和不需要拓展, 如果傳入的type為1或者2,則生成checkbox或者radio,由于radio樣式比較丑,用label包起來自己模擬選中的效果;如果傳入拓展參數(shù),則把當(dāng)前的父級li以及當(dāng)前的參數(shù)傳入,以便進(jìn)行拓展。


   $("#tree").append(render(json,{
    type:1,
    expandDom:function(el,data){
     el.append("<button>編輯</button><button>測試</button><a data-msg='"+JSON.stringify(data)+"'></a>")
    }
   }))

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

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++) {
   // 以每條數(shù)據(jù)的id作為obj的key值,數(shù)據(jù)作為value值存入到一個臨時對象里面
   tmpMap[treeArray[i]["id"]]= treeArray[i]; 
  } 

  for (i=0, l=treeArray.length; i<l; i++) {
   var key=tmpMap[treeArray[i]["pid"]];
   
   //循環(huán)每一條數(shù)據(jù)的pid,假如這個臨時對象有這個key值,就代表這個key對應(yīng)的數(shù)據(jù)有children,需要Push進(jìn)去
   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
  }

現(xiàn)在我們已經(jīng)實現(xiàn)了將沒有層級結(jié)構(gòu)的數(shù)組轉(zhuǎn)化為帶有層級的數(shù)組,那么問題來了,樹形圖還常常會需要帶搜索功能,有沒有辦法把帶層級結(jié)構(gòu)的數(shù)組轉(zhuǎn)化為不帶層級結(jié)構(gòu)的一個數(shù)組呢?因為如果不帶層級的話,進(jìn)行搜索等操作時就非常方便,一個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到最外層的數(shù)組r里面
      r = r.concat(jsonToArray(nodes[i]["children"]));
       delete nodes[i]["children"]
    }
   } 
   return r;
  }

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

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

為了不影響到原來的數(shù)據(jù),我們需要復(fù)制一份數(shù)據(jù),需要進(jìn)行一次深拷貝。

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

對于標(biāo)準(zhǔn)的json格式的對象,可以用JSON.parse(JSON.stringify(obj))來實現(xiàn)。當(dāng)然,本文寫的是遞歸,所以還是來手寫一個

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
  }
 }

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

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

jsonToArray(deepCopy(data));

亦或是

arrayToJson(deepCopy(data)):

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • TypeScript枚舉的基礎(chǔ)知識及實例

    TypeScript枚舉的基礎(chǔ)知識及實例

    使用枚舉我們可以定義一些帶名字的常量,使用枚舉可以清晰地表達(dá)意圖或創(chuàng)建一組有區(qū)別的用例,下面這篇文章主要給大家介紹了關(guān)于TypeScript枚舉的基礎(chǔ)知識及實際用例,需要的朋友可以參考下
    2021-10-10
  • 基于javascript實現(xiàn)表格的簡單操作

    基于javascript實現(xiàn)表格的簡單操作

    這篇文章主要為大家詳細(xì)介紹了基于javascript實現(xiàn)表格的簡單操作,具有一定的參考價值,感興趣的朋友可以參考一下
    2016-05-05
  • Javascript 匿名函數(shù)及其代碼模式原理

    Javascript 匿名函數(shù)及其代碼模式原理

    很多同學(xué)知道怎么用這種匿名函數(shù),卻或許并不明白為什么這樣寫就能夠調(diào)用匿名函數(shù)。也許知道后面的圓括號是執(zhí)行前面的函數(shù),而并不清楚前面的圓括號具有何種含義!本文將帶你了解匿名函數(shù)的代碼模式原理。
    2010-03-03
  • 微信小程序?qū)崿F(xiàn)image組件圖片自適應(yīng)寬度比例顯示的方法

    微信小程序?qū)崿F(xiàn)image組件圖片自適應(yīng)寬度比例顯示的方法

    這篇文章主要介紹了微信小程序?qū)崿F(xiàn)image組件圖片自適應(yīng)寬度比例顯示的方法,簡單講述了image組件的常用屬性,并結(jié)合實例形式分析了微信小程序?qū)崿F(xiàn)圖片自適應(yīng)寬度比例的相關(guān)操作技巧,需要的朋友可以參考下
    2018-01-01
  • Javascript 顏色漸變效果的實現(xiàn)代碼

    Javascript 顏色漸變效果的實現(xiàn)代碼

    在搭建博主博客的時候,尋思著做一些效果,看到菜單,就想是不是可以做一下顏色的漸變,增加一點動態(tài)的感覺。有個jquery的插件,效果相當(dāng)不錯,不過博主還是打算自立更生寫一下,看看能不能實現(xiàn)
    2013-10-10
  • 原生js輪播(仿慕課網(wǎng))

    原生js輪播(仿慕課網(wǎng))

    本文主要分享了原生js實現(xiàn)仿慕課網(wǎng)的輪播效果。具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02
  • ES6基礎(chǔ)之默認(rèn)參數(shù)值

    ES6基礎(chǔ)之默認(rèn)參數(shù)值

    這篇文章主要介紹了ES6基礎(chǔ)之默認(rèn)參數(shù)值,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • iscroll動態(tài)加載數(shù)據(jù)完美解決方法

    iscroll動態(tài)加載數(shù)據(jù)完美解決方法

    這篇文章主要為大家詳細(xì)介紹了iscroll動態(tài)加載數(shù)據(jù)的完美解決方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • JS實現(xiàn)彈性菜單效果代碼

    JS實現(xiàn)彈性菜單效果代碼

    這篇文章主要介紹了JS實現(xiàn)彈性菜單效果代碼,可實現(xiàn)鼠標(biāo)滑過后背景色滑塊彈性滑過的效果,非常具有實用價值,需要的朋友可以參考下
    2015-09-09
  • css 二級菜單 實現(xiàn)代碼集合 修正版

    css 二級菜單 實現(xiàn)代碼集合 修正版

    最近的網(wǎng)站要求使用二級菜單,本著“能用別人的就用別人的,不能用別人的就用自己的”的原則,在網(wǎng)上找到一個經(jīng)典的使用CSS制作的二級菜單,感覺不錯,先記錄下來,以備它用。
    2009-06-06

最新評論