章鱼哥的第二个春天的最后一个星期日早晨太阳起来的太早把他烤成了八爪鱼干
如题所述【作者:mr.kao】(未满18岁者以下链接谨点!)
js递归遍历树
2010-05-27 07:26:11

树的结构可以很简单的看着是N个父子关系,这和许多Object就很像,在JAVA中往map中放map这可以很好的表现出这种关系。基于这种关系,从某个节点出发,把他们遍历出来也是很简单的事情。

所以首先我们把一组有父子关系的数据放在一个OBJECT里面,并封装一个treeList类。往往这一步是在最初始的时候做,所以可以写这样的一个方法:

initData:function(arr){//arr是一组有父子关系的数据,这里的关系表现在parentId和id两个字段上。当然可以是其他字段。
  for(var i=0; i   if(!treeList.treeData[arr[i].parentId]){
    treeList.treeData[arr[i].parentId] = {};//用parentId作为所有父节点的KEY
   treeList.treeData[arr[i].parentId][arr[i].id] = arr[i];//arr[i].id作为某个具体孩子节点对象的KEY
  }
 },

一组数据都有一个值不可重复的主键,比如这里的ID。praentId其实指向的是也是某个ID,拿这个ID作为KEY,是比较靠谱的一种做法。

下面就可以遍历整个树了。可以从一节点pid开始遍历。

getTree:function(pid){
  for(var k in treeList.treeData[pid]){
   if(treeList.treeData[k]&&k!=0){
    treeList.getTree(k);//如果有值为K的父节点,递归查找他的孩子节点
   }
   treeList.treeData[pid][k];//这里的treeList.treeData[pid][k]就是key值为pid下面的孩子节点对象
  }
 }
一切就就是这样简单!
按照这个方法,在一个项目中我写了下面的一个类,主要是在DOM里插入和操作这棵树。

/*
* treeList : tree control class of operation menu
* 操作菜单树结构控制类
* by : tangq
* version : 1.0
* date: 2010-4-14
* updateTime: 2010-4-15

*/
var treeList = {
 /*
 * [object treeList.treeData] : The format of data stored in the treeData
 * 将格式后的数据存储在treeData
 */
 treeData:{},
 /*
 * [String treeList.htmlDom] : 
 * 当前treelist生成的HTMLElement
 */
 htmlDom:[],
 /*
 * [funtion treeList.init] : initialization treeList, and HTML text into the specified domElement inside.
 * 在DOM中初始化treeList,并将HTML文本插入指定的domElement里面。
 * @param id[String] : dom中节点的ID
 */
 init:function(id,model){
  if(model){
   treeList.model = model; 
  }
  /*
  * 默认状态下从0级开始遍历树
  */
  if(treeList.treeData[0]){
   treeList.getTree(0);
  }
  /*
  * 将一个DOMlist添加到当前document中
  */
  var dom = document.createElement('ul');
  dom.id = 'treelist-box';
  dom.className = 'treelist';
  for(var i=0; i   dom.appendChild(treeList.htmlDom[i]);
  }
  document.getElementById(id).appendChild(dom);
  
 },
 /*
 * [funtion treeList.get] : Get a property in treelist object
 * 得到treelist对象里的某个属性值
 * @param id[number] : 元数据的ID  treeList.treeData的KEY值
 * @param value[string] : 要属性的 若改属性不存在 返回null
 */
 get:function(id,value){
  for(var p in treeList.treeData){
   for(var k in treeList.treeData[p]){
    if(k==id){
     if(treeList.treeData[k])return null;
     return treeList.treeData[p][k][value];
    }
   }
  }
  return null;
 },
 /*
 * [funtion treeList.initData] : External call interface of data initially treelist
 * 外部调用接口 初始treelist的数据
 * @param arr[Array] : 外部获取的一个treelist数组
 */
 initData:function(arr){
  treeList.htmlDom = [];
  for(var i=0; i   if(!treeList.treeData[arr[i].parentId]){
    treeList.treeData[arr[i].parentId] = {};
   }
   treeList.treeData[arr[i].parentId][arr[i].id] = arr[i];
  }
 },
 /*
 * [String model]:设置节点模板类型
 */
 model:'icon',
 /*
 * [funtion treeList.getTmpStr] : Generating node template
 * 生成节点模版
 */
 getTmpStr:function(){
  if(treeList.model=='icon'){
   return '#name#'; 
  }
  if(treeList.model=='checkbox'){
   return '#name#'; 
  }
  if(treeList.model=='none'){
   return '#name#'; 
  }
  return '';
 },
 /*
 * [funtion treeList.getTree] : The depth of a parent node traversal
 * 对一个父节点进行深度遍历
 * @param pid[Number] : 节点ID
 * EXP:getTree(0)-> 遍历父节点为0下的所有子节点
 */
 getTree:function(pid){
  var modelstr = treeList.getTmpStr();
  for(var k in treeList.treeData[pid]){
   var dom = document.createElement('li');
   dom.id = 'treelist-'+k;
   var s = modelstr.replace(/#id#/g,k).replace(/#name#/g,treeList.treeData[pid][k].name).replace(/#value#/g,treeList.treeData[pid][k].value);
   if(treeList.treeData[k]&&k!=0){
    dom.className = 'treelist-level-'+pid+' treelist-parentNode';
    dom.innerHTML = ''+s;
    treeList.htmlDom.push(dom);
    treeList.getTree(k);
   }else{
    dom.className = 'treelist-level-'+pid;
    dom.innerHTML = ''+s;
    treeList.htmlDom.push(dom);
   }
   treeList.treeData[pid][k].dom = dom;
   (function(dom,k){
    dom.onclick = function(){
     treeList.click(k);
    };
   })(dom,k);
  }
 },
 /*
 * [funtion treeList.click] : node's click Event
 * 节点点击事件
 * @param id[Number] : 节点索引值,0开始
 * 如果是父节点 将调用父节点事件
 */
 click:function(id){
  for(var p in treeList.treeData){
   for(var k in treeList.treeData[p]){
    if(k==id){
     if(treeList.treeData[k]){
      treeList.parentClick(k);
     }else{
      treeList.select('treelist-'+k);
     }
     break;
    }
   } 
  }
 },
 /*
 * [funtion treeList.parentClick] : node's click Event
 * 父节点节点点击事件
 * @param id[Number] : treeList.treeData的KEY值 即元数据某一对象的ID
 * 收起或展开子节点
 */
 parentClick:function(id,m){
  var lispan = document.getElementById('treelist-'+id).getElementsByTagName('span').item(0);
  var action;
  if(!m){
   if(lispan.className.indexOf('treeicon-open')!=-1){
    action = 'close';
   }else{
    action = 'open';
   }
  }else{
   action = m; 
  }
  for(var k in treeList.treeData[id]){
    if(treeList.treeData[k]){
     treeList.parentClick(k,action);
    }
  }
  var lis = document.getElementById('treelist-box').getElementsByTagName('li');
  for(var i=0; i   if(lis.item(i).className.indexOf('treelist-level-'+id)!=-1){
    if(action=='open'){
     lis.item(i).style.display = 'block';
    }else{
     lis.item(i).style.display = 'none'; 
    }
   } 
  }
  if(action=='open'){
   lispan.className = lispan.className.replace('treeicon-close','treeicon-open');
  }else{
   lispan.className = lispan.className.replace('treeicon-open','treeicon-close');
  }
  
 },
 /*
 * [funtion treeList.select] : A node is selected
 * [String|Number treeList.selectedIndex] : tree selected Index or id
 * 选中某个节点
 * @param num[Number] : 节点索引值,0开始
 */
 selectedIndex:null,
 select:function(index){
  selectedIndex = treeList.selectedIndex;
  if(index==selectedIndex)return;
  for(var i=0; i   if(index.constructor == Number&&index==i){
    treeList.htmlDom[index].className += ' selected';
   }else if(treeList.htmlDom[i].id == index){
    treeList.htmlDom[i].className += ' selected';
   }
   if(selectedIndex!=null&&selectedIndex.constructor == Number&&selectedIndex==i){
    treeList.htmlDom[i].className = treeList.htmlDom[i].className.replace(' selected','');
   }else if(selectedIndex!=null&&treeList.htmlDom[i].id == selectedIndex){
    treeList.htmlDom[i].className = treeList.htmlDom[i].className.replace(' selected','');
   }
  }
  
  treeList.selectedIndex = index;
 },
 /*
 * [funtion treeList.addEvent] : Add a events to treelist nodes
 * 给treelist节点添加监听事件
 * @param type[String] : 事件类型
 * @param fun[function] : 回调函数
 */
 addEvent:function(type,fun){
  for(var i=0; i   (function(dom,type,fun){
        xui.util.Event.on(dom,type,fun);
       })(treeList.htmlDom[i],type,fun); 
  }
 }
}

/*
* examples
*/

/*
treeList.getTree(0);
alert(treeList.html);
*/
/*
* used it in html:

code in head:

code in dom:

code when dom loaded:

*/
示例中common.css为树HTML结构的样式,treelist.js是数据源,可以是这样的:

var arry = [{"parentId":"0","id":0,"name":"根","link":"www.g.cn"}......];

然后初始化它:treeList.initData(arry);

 

js,javascript,java,web,wd,map
  • Mr.kao
  • web
  • 116
  • 0