TreeTable的简单实现

最终效果图:



UI说明:针对table本身进行增强的tree table组件。
tree的数据来源是单元格内a元素的自定义属性:level和type。具体代码如下:

Java代码 复制代码 
  1. <table id="treeGrid" border="0" cellpadding="0" cellspacing="0">   
  2.   <THEAD>   
  3.         <tr><th>Department</th><th>EmployeeID</th><th>position</th></tr>       
  4.   </THEAD>   
  5.   <TBODY>   
  6.         <tr><td width="250px"><a level="0" type="node" href="javascript:void(0);">Dept4</a></td><td>-</td><td>-</td></tr>   
  7.         <tr><td><a level="1" type="leaf" href="javascript:void(0);">fanggw</a></td><td>c3025</td><td>MASTER</td></tr>   
  8.         <tr><td><a level="1" type="node" href="javascript:void(0);">team1</a></td><td>-</td><td>-</td></tr>   
  9.         <tr><td><a level="2" type="leaf" href="javascript:void(0);">zhanghy</a></td><td>c3268</td><td>SE</td></tr>   
  10.         <tr><td><a level="2" type="leaf" href="javascript:void(0);">chenf</a></td><td>c3401</td><td>SE</td></tr>   
  11.    </TBODY>   
  12. </table>  
<table id="treeGrid" border="0" cellpadding="0" cellspacing="0">
  <THEAD>
  		<tr><th>Department</th><th>EmployeeID</th><th>position</th></tr>	
  </THEAD>
  <TBODY>
		<tr><td width="250px"><a level="0" type="node" href="javascript:void(0);">Dept4</a></td><td>-</td><td>-</td></tr>
		<tr><td><a level="1" type="leaf" href="javascript:void(0);">fanggw</a></td><td>c3025</td><td>MASTER</td></tr>
		<tr><td><a level="1" type="node" href="javascript:void(0);">team1</a></td><td>-</td><td>-</td></tr>
		<tr><td><a level="2" type="leaf" href="javascript:void(0);">zhanghy</a></td><td>c3268</td><td>SE</td></tr>
		<tr><td><a level="2" type="leaf" href="javascript:void(0);">chenf</a></td><td>c3401</td><td>SE</td></tr>
   </TBODY>
</table>


根据上述数据源结构,先遍历该table,读取数据并建立整课树的数据模型,然后初始化整棵树的视图(node和leaf的显示由css样式定义,方便修改,如果需要可以进一步在初始化的时候由外部代码指定),并关联节点的click处理程序。

下面是主要的实现代码:

Java代码 复制代码
  1.   
  2. var Class = {   
  3.   create: function() {   
  4.     return function() {   
  5.       this.initialize.apply(this, arguments);   
  6.     }   
  7.   }   
  8. }   
  9.      
  10.   var Node = Class.create();   
  11.   Node.prototype = {   
  12.     initialize: function(link, level, type) {   
  13.         this.name = link.innerText;         
  14.       this.id;   
  15.       this.link = link;   
  16.       this.type = type;   
  17.       this.level = level;      
  18.       this.isOpen = true;   
  19.       this.isClicked = false;   
  20.       this.root;   
  21.       this.img; //clicked img's path   
  22.   
  23.         this.parent;   
  24.       this.children = new Array();   
  25.       this.getChildren();   
  26.          
  27.     },   
  28.        
  29.     getChildren: function() {   
  30.         if (this.type == "node") {   
  31.             //alert(this.link.innerText);   
  32.         var dataRows = document.getElementById("treeGrid").getElementsByTagName("TBODY")[0].getElementsByTagName("TR");   
  33.         var pushFlag = false;   
  34.            
  35.         for(var j=0; j<dataRows.length; j++) {   
  36.             var linkTag = dataRows[j].firstChild.firstChild;   
  37.             var level = linkTag.getAttribute("level");   
  38.             var type = linkTag.getAttribute("type");   
  39.                
  40.             if (!pushFlag) {   
  41.                 if (linkTag == this.link) {   
  42.                     pushFlag = true;   
  43.                 }   
  44.                 continue;   
  45.             }   
  46.             //alert("cur lvl:"+level+"; type:"+type +" ;parentLvl:" +(parseInt(this.level)+1));   
  47.                
  48.             if (level == (parseInt(this.level)+1)) {   
  49.                 //alert("push node's lvl:"+level+"; type:"+type);   
  50.                 var leaf = new Node(linkTag, level, type);   
  51.                 leaf.parent = this;   
  52.                 leaf.id = level+"_"+j;   
  53.                 this.children.push(leaf);   
  54.             } else if (level == this.level) {   
  55.                 break;   
  56.             } else {   
  57.                 continue;   
  58.             }   
  59.                
  60.         }   
  61.         }   
  62.         //for (var i=0; i<this.children.length; i++) {   
  63.             //this.children[i].parent = this;   
  64.         //}   
  65.         //alert("childs:"+this.children.length);   
  66.     },   
  67.        
  68.     getNext: function() {   
  69.         var next = null;   
  70.         //alert(this.name);   
  71.            
  72.         if (this.parent) {   
  73.         for (var i=0; i<this.parent.children.length; i++) {   
  74.             if (this.parent.children[i] == this && i < (this.parent.children.length-1)) {   
  75.                 next = this.parent.children[i+1];   
  76.                 break;   
  77.             }   
  78.         }      
  79.         }   
  80.         /*  
  81.         if (next)  
  82.             alert("next:"+next.name);  
  83.         else   
  84.             alert("current is last");  
  85.         */  
  86.         return next;   
  87.     },   
  88.        
  89.        
  90.     getCurrentRow: function() {   
  91.         return this.link.parentNode.parentNode.parentNode;             
  92.     },   
  93.        
  94.     changeClickImg: function() {   
  95.         if (this.isOpen) {   
  96.             this.img.src = this.img.src.replace("minus""plus");   
  97.         } else {   
  98.             this.img.src = this.img.src.replace("plus","minus");   
  99.         }   
  100.         this.isOpen = this.isOpen?false:true;   
  101.     },   
  102.        
  103.     getInnerHTML: function() {   
  104.         var oFragment = document.createDocumentFragment();   
  105.            
  106.         //make the indent img by level   
  107.     for (var lvl = this.level-1; lvl>0; lvl--) {   
  108.         var indentImg = document.createElement("img");   
  109.            
  110.         //get parent node by level   
  111.         var parentNode = this.parent;   
  112.         for (var i=1; i<lvl; i++) {   
  113.             parentNode = parentNode.parent;   
  114.         }   
  115.            
  116.         //alert(this.name+":"+parentNode.name);   
  117.         //alert(parentNode.getNext()?parentNode.getNext().name:"null");   
  118.            
  119.         /* parent node has nextSibling insert vertical line img */  
  120.         if (parentNode.getNext()) {   
  121.             indentImg.src = "./images/I.gif";   
  122.         } else {   
  123.             /* parent node has nextSibling insert blank img */  
  124.             indentImg.src = "./images/blank.gif";   
  125.         }   
  126.             indentImg.align = "absbottom";   
  127.             oFragment.appendChild(indentImg);   
  128.         }   
  129.   
  130.            
  131.         //make the plus or minus img   
  132.         var img = document.createElement('img');   
  133.         var path;   
  134.         if (this.type == "node") {   
  135.             if (this.level == 0) {   
  136.                 path = "./images/minus.gif";   
  137.             } else {   
  138.                 if (this.children.length > 0) {   
  139.                     if (this.getNext()) {   
  140.                         path = "./images/Tminus.gif";   
  141.                     } else {   
  142.                         path = "./images/Lminus.gif";   
  143.                     }   
  144.                 }   
  145.                 else {   
  146.                     if (this.getNext()) {   
  147.                         path = "./images/T.gif";   
  148.                     } else {   
  149.                         path = "./images/L.gif";   
  150.                     }   
  151.                 }   
  152.             }                  
  153.         } else {   
  154.                 if (this.getNext()) {   
  155.                     path = "./images/T.gif";   
  156.                 }   
  157.                 else {   
  158.                     path = "./images/L.gif";   
  159.                 }    
  160.         }   
  161.         img.src = path;   
  162.       img.align = "absbottom";   
  163.       //set cursor pointer style to the minus/plus img   
  164.       img.style.cursor = "pointer"  
  165.       this.img = img;   
  166.       img.onclick = expand;   
  167.          
  168.       oFragment.appendChild(img);   
  169.       oFragment.appendChild(this.link);   
  170.          
  171.       var div = document.createElement("div");   
  172.       div.setAttribute("id"this.id);   
  173.   
  174.       /* div css class set by type */  
  175.       div.className = (this.type=="node")?"node":"leaf";    
  176.          
  177.       /* all node is margin to left by 10 pixel except root */  
  178.       if (this.level > 0) {   
  179.           div.style.marginLeft = "10px";   
  180.       }   
  181.          
  182.         div.appendChild(oFragment);   
  183.         return div;   
  184.            
  185.     }   
  186.   }   
  187.      
  188.   /* global variable */  
  189.   //tree root   
  190.   var root;   
  191.   //all nodes of the tree   
  192.   var nodes = new Array();   
  193.      
  194.   /* initialize the whole tree grid */  
  195.   function initTreeGrid() {   
  196.   //dataRows is the datasource of the tree   
  197.     var dataRows = document.getElementById("treeGrid").getElementsByTagName("TBODY")[0].getElementsByTagName("TR");   
  198.        
  199.     //find the root of the tree   
  200.         for (var i=0; i<dataRows.length; i++) {   
  201.             var linkTag = dataRows[i].firstChild.firstChild;   
  202.             var level = linkTag.getAttribute("level");   
  203.             var type = linkTag.getAttribute("type");   
  204.                
  205.             if (level == 0 && type == "node") {   
  206.                 var root = new Node(linkTag, 0"node");   
  207.                 root.parent = null;   
  208.                 root.id = "0_0";   
  209.                 break;   
  210.             }   
  211.         }   
  212.            
  213.         //put all node into 1-index array   
  214.         nodes.push(root);   
  215.         initNodes(root);   
  216.            
  217.         //display the table tree   
  218.         for (var j = 0; j<nodes.length; j++) {   
  219.             dataRows[j].firstChild.appendChild(nodes[j].getInnerHTML());   
  220.         }   
  221.   }   
  222.      
  223.   function initNodes(node) {   
  224.       for (var j=0; j<node.children.length; j++) {   
  225.             nodes.push(node.children[j]);   
  226.             if (node.children[j].children.length > 0) {   
  227.                 initNodes(node.children[j]);   
  228.             }   
  229.         }   
  230.   }   
  231.      
  232.   /* expand row elements by isOpen flag */  
  233.   function expand() {          
  234.     var currentDivId = event.srcElement.parentNode.id;   
  235.     var currentNode;   
  236.        
  237.     //get the clicked node   
  238.     for(var i=0; i<nodes.length; i++) {   
  239.         if (currentDivId == nodes[i].id) {   
  240.             currentNode = nodes[i];   
  241.             break;   
  242.         }   
  243.     }   
  244.        
  245.     //expand the clicked node   
  246.     expandChild(currentNode);   
  247.        
  248.     //set the isClicked flag when the row minus img is clicked   
  249.     currentNode.isClicked = currentNode.isClicked?false:true;   
  250.   }   
  251.      
  252.   function expandChild(currentNode) {   
  253.     //alert(currentNode.name);   
  254.     for (var i=0; i<currentNode.children.length; i++) {   
  255.         var child = currentNode.children[i];   
  256.         if (child.type == "node" && !child.isClicked) {   
  257.             expandChild(child);   
  258.         }   
  259.         child.getCurrentRow().style.display = currentNode.isOpen?"none":"block";   
  260.     }   
  261.     currentNode.changeClickImg();   
  262.   }   
  263.   
  264. /* utility function */  
  265. function addEvent(obj, evType, fn) {   
  266.     /* adds an eventListener for browsers which support it  
  267.        Written by Scott Andrew: nice one, Scott */  
  268.     if (obj.addEventListener) {   
  269.         obj.addEventListener(evType, fn, true);   
  270.         return true;   
  271.     }   
  272.     else if (obj.attachEvent) {   
  273.         var r = obj.attachEvent("on"+evType, fn);   
  274.         return r;   
  275.     }   
  276.     else {   
  277.         return false;   
  278.     }   
  279. }   
  280.   
  281. /* add load event to body element*/  
  282. addEvent(window, "load", initTreeGrid);  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值