一颗面向对象的javaScript树

来源:互联网 发布:数据港董事长周群 编辑:程序博客网 时间:2024/06/01 13:41

首先声明这颗树是根据project_tree_pub 修改 。

先来两个从prototype.js中抄袭过来的代码

var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}
function emptyFunction() {}

长期写Java代码,突然转到javascript,发现程序不那么好写,想来想去是javascript少了java.util.*包里面的类,
于是用javascript实现了List,Map两个类,这棵树只用到了List类,List类在我另外写的一个AjaxServer类里面可以转换成XML,然后传送给服务器端解析成java.util.ArrayList类,并且完美的嵌入了struts框架
/*    List类
     服务器端解析成java.util.ArrayList
*/
List =Class.create();
List.prototype={
 initialize: function(){
  this.className='java.util.ArrayList';  
  this._data=null;
  this._data=new Array;
  this._size=0;
 },
 size:function(){
  return this._size;
 },
 indexOf:function(key){
  var index=-1;
  var i=0;
  for(i=0;i<this._size;i++){
   if(key==this._data[i]){
    index=i;
    break;
   }
  }
  return index;
 },
 insert:function(index,key){
  var i=0;
  if(index>=this._size){
    this._data[this._size]=key;
    this._size++;
    return;
  }
  for(i=this._size-1;i>this._size-index;i--){
   this._data[i+1]=this._data[i];
  }
  this._data[index]=key;
 },
 add:function(key){
  this.insert(this._size,key);
 }, 
 get:function(index){
  if(index<0||index>=this._size)
   return null;
  return  this._data[index];
 },
 remove:function(index){
  var i=0;
  if(index<0||index>=this._size)
   return;
  for(i=index;i<this._size-1;i++){
   this._data[i]=this._data[i+1];
  }
  if(this._size>0)
   this._data[this._size-1]=null;
  this._size--;
 },
 clear:function(){
  this.initialize();
 }
}
下面是节点类,表示树的每一个节点,用List表示它的儿子们,_parentNode指向它的父亲,
_level表示节点所处在的层次,nodeID是节点的唯一标示,一颗树的每一个节点的ID必须唯一,这里在程序里面没有作控制^_^
_state 表示节点的状态,打开还是关闭的。

/*节点类*/
Node =Class.create();
Node.prototype={
 /**构造函数
   *节点id(必须唯一),节点显示名称,关联url,节点默认状态('open','closed') 
   */
   initialize:function(id,name,url,status){
    this._children = new List();
    this._url = url; 
    this._nodeID=id;  
    this._name=name;
    this._state = status ;
    this._level=0;
    this._parentNode=null;
 },
 setParentNode:function(prentNode){
  this._parentNode=prentNode;
 },
 getParent:function(){
  return this._parentNode;
 },
 getChildren:function(){
  return this._children;
 },
 getURL : function(){
  return this._url;
 },
 getNodeID : function(){
  return this._nodeID;
 },
 getName : function(){
  return this._name;
 },
 getState : function(){
  return this._state;
 },
 setState : function(state){
  this._state=state;
 },
 getLevel : function(){
  return this._level;
 },
 /**设置状态*/
 setState : function(status){
    this._state=status;
 },
 
 /**设置URL*/
 setUrl : function(url){
    this._url=url;
 },
 /**删除一个字节点*/
 removeChild:function(nodeID){
  var i=0;
  var node=null;
  for(i=0;i<this._children.size();i++){
   node=this._children.get(i);
   if(node.getNodeID()==nodeID){
      this._children.remove(i);
      break;
   }
  }
 },
 /**设置儿子*/
 setChildren : function(children){
     var i=0;
     if(children instanceof List){
   this._children=children;
   for(i=0;i<children.size();i++){  
     children.get(i).setParentNode(this);
     this.setLevel(this._level);
   }
  }else{
   alert('属性不对无法加入!');
  }

 },
 /**添加一个儿子*/
 addChildNode : function(childNode){
   if(childNode==this){
  alert('子节点不能是本身');
  return;
   }
   if(childNode instanceof Node){
         this._children.add(childNode);
         this.setLevel(this._level);
   childNode.setParentNode(this);
   }else{
      alert('属性不对无法加入!');
   }
 },
 /**设置子节点级别*/
 setLevel : function (level){
     var i=0;
  this._level=level;
  for(i=0;i<this._children.size();i++){
   this._children.get(i).setLevel(level+1);
  }

 },
 /**获得节点类型*/
 getNodeType:function(){
  var type='leaf';
  if( this._children.size()>0)
   type='node';
  return type;
 }
}

下面来看Tree类,先来看看他的属性,nodeList是一个根节点的List,
_treeName表示在javascript里面定义树变量的名称,通过构造函数传入
currentNodeID当前选择的节点
onClick 初始化为空函数,用户要响应点击树节点事件,必须重载此函数
removeNode(nodeID) 删除一个节点
getNode(nodeID)根据节点编号找到Node对象
repaint()当树的结构发生变化时必须调用此方法重画树
getTree()获得定义树的HTML,只有初始化树时候调用,其它时候请调用repaint()重画树
/*********************树类***************/
Tree =Class.create();
Tree.prototype={
     /**构造函数*/
  initialize: function(treeName){
   this.nodeList=new List();
   this._outStr='';
   this._treeName=treeName;
     this.currentNodeID="";
   this.onClick=emptyFunction;
   /*是否采用异步请求的方式*/
   this.isAsync=false;
  },
 splitChar : "&nbsp;&nbsp;",  //每个层次间的分隔符
 img_opennode : "images/folderopen.gif",
 img_node : "images/folder.gif",
 img_leaf : "images/page.gif",
 img_selnode : "images/foldersel.gif",
 img_selopennode : "images/folderopensel.gif",
 img_selleaf : "images/pagesel.gif",
 img_nodeisclick : "images/open.gif",
 img_nodenotclick : "images/plus.gif",
 img_split : "&nbsp;&nbsp;",
  /**获得当前的节点*/
  getCurrentNode:function(){
  if(this.currentNodeID!=''){
   return this.getNode(this.currentNodeID);
  }
  return null;
  },
  /**设置根节点*/
  addRoot:function(root){
    this.nodeList.add(root);
  },
  /**删除节点*/
  removeNode : function(nodeID){
     var i=0;
  var node=this.getNode(nodeID);
  if(node==null){
   alert('找不到节点:'+nodeID);
   return;
  }

  if(node.getParent()==null){
   for(i=0;i<this.nodeList.size();i++){
    if(this.nodeList.get(i).getNodeID()==nodeID){
     this.nodeList.remove(i);
     break;
    }
   }
  }else{
   node.getParent().removeChild(nodeID);
  }
  if(this.currentNodeID==nodeID)
     this.currentNodeID='';
  },
  /**根据节点编号获得节点*/
  getNode:function(nodeID){
  var i=0;
  var node=null;
  for(i=0;i<this.nodeList.size();i++){
   node=this.getChildNode(this.nodeList.get(i),nodeID);
   if(node!=null)
      break;
  }
  return node;
  },
  /**根据节点编号获得节点*/
  getChildNode:function(node,nodeID){
     var retNode=null;
  var i=0;
  if(node.getNodeID()==nodeID)
     return node;
   for(i=0;i<node.getChildren().size();i++){
   retNode=this.getChildNode(node.getChildren().get(i),nodeID);
   if(retNode!=null)
    break;
   }
  return retNode;
  },
  /**重画树*/
  repaint: function(){
       this._outStr='';
    for(i=0;i<this.nodeList.size();i++){
      var node=this.nodeList.get(i);
    this.printTree(node,'open',0);
    }
    document.getElementById("kuyuer_"+this._treeName).innerHTML=this._outStr;
  },
  /**生成树*/
  getTree:function(){
       var i=0;
      this._outStr="<div id='kuyuer_"+this._treeName+"'>";
    for(i=0;i<this.nodeList.size();i++){
      var node=this.nodeList.get(i);
    this.printTree(node,'open',0);
    }
    this._outStr+="</div>";
    return this._outStr;
  },
 /*
  * 输出整个树的页面展现字符串
  */
   printTree:function (tempNode,parentStatus,level){  
  var i=0;
  var childLength=tempNode.getChildren().size();
  this._outStr=this._outStr+this.printNode(tempNode,parentStatus,level)
  if(childLength>0){
   for(i=0;i<childLength;i++){
    this.printTree(tempNode.getChildren().get(i),tempNode.getState(),level+1);
   }
  }
  this._outStr=this._outStr+"</div>";   
   } ,
 

 /*
  * 输出对应节点的页面展现字符串
  * 参数说明:节点对应,父节点的节点状态
  */
 printNode:function(tempNode,parentStatus,level){
     var childLength=tempNode.getChildren().size();
     var style_display="display:block";
     var boundstr="";
     var nodestr="";
     var imgsrc="";
     var imgstatus="";

  /*父节点处于关闭状态,子结点包括其子节点都不显示*/
     if(parentStatus=="closed")
         style_display="display:none";
  if(childLength>0){
     if(tempNode.getState()=='open'){
     imgsrc=this.img_opennode;       
     imgstatus=this.img_nodeisclick; 
     }
     else{
     imgsrc=this.img_node;
     imgstatus=this.img_nodenotclick; 
     }
  }else{
     imgsrc=this.img_leaf;  
  }
  
     for(j=0;j<level;j++){
        boundstr += this.splitChar;
     }

     /*是结点*/
     if(childLength>0){     
   nodestr="<div id='" + tempNode.getNodeID() +"'  style='" + style_display+"' >"+boundstr
    +"<img  imgtype='status' onclick=/""+this._treeName+".nodeClick(this,'"+tempNode.getNodeID()+"')/"  src='"+imgstatus+"' >"
    +"<img  imgtype='node' src=/""+imgsrc+"/" >" ;
    if(tempNode.getURL()=='')
    nodestr+=tempNode.getName();
    else
    nodestr+="<a style='cursor:hand' onclick=/""+this._treeName+".nameClick(this,'"+tempNode.getNodeID()+"')/">"
              + tempNode.getName()+"</a>";
     }

     /*树叶*/  
     else{
        nodestr="<div id='" + tempNode.getNodeID() +"'  style='" +style_display+"' >"+boundstr
        +this.img_split+"<img src='"+imgsrc+"'  imgtype='node' >";
     if(tempNode.getURL()=='')
    nodestr+=tempNode.getName();
     else
           nodestr+="<a style='cursor:hand' onclick=/""+this._treeName+".nameClick(this,'"+tempNode.getNodeID()+"')/">"
                + tempNode._name+"</a>";
     }
     return nodestr;
 },

 /*
  * 根据id获取对应图层对象,解析页面子节点,更新点击后的节点图片和状态图片,更新对应子节点显示
  */
 nodeClick:function(src,nodeid){
    var obj=document.getElementById(nodeid); 
    var node=this.getNode(nodeid);
    var childobj="";
    var childlength=obj.childNodes.length; 
    /**节点状态*/
    var nodestatus="";
    /**是否取得了子节点*/
    var synstus="no";
    var nodesplitlength=0;

    /*动态生成子节点*/
    if(this.isAsync ){
    /*对应节点的分隔符*/
    nodesplitlength=obj.childNodes[0].nodeValue.length;
    for(i=0;i<childlength;i++){
    childobj=obj.childNodes[i];
    if(childobj.tagName!=null){
      if(childobj.tagName.toUpperCase()=="DIV"){
       synstus="yes";     
       break;
      }  
    }
     }
     /*尚未同步*/      
     if(synstus=="no"){
    /*
    *需要去服务器获得节点信息
    */
    /*更新节点后重新获取子节点长度*/
    childlength=obj.childNodes.length;
    nodestatus="open";
     }
     else{
    nodestatus="closed";
     } 
    } 
    /*只有异步生成html或者不是异步生成的触发该事件*/
    if(this.isAsync==false||synstus=="yes"){
   for(i=0;i<childlength;i++){
     childobj=obj.childNodes[i];
     if(childobj.tagName!=null){         
      if(childobj.tagName.toUpperCase()=="DIV"){                  
      if(childobj.style.display=="block"){
       childobj.style.display="none";
       nodestatus="closed"; 
      }
      else{
       childobj.style.display="block"; 
       nodestatus="open";
      }
      }
   
     }
   }
    }
   
    for(i=0;i<childlength;i++){
    childobj=obj.childNodes[i];
    if(childobj.tagName!=null){
    if(childobj.tagName.toUpperCase()=="IMG"){
     
    //if(event.srcElement==childobj){
    if(src==childobj){
     /*异步请求不需要再重新判断当前节点状态*/
     if(synstus!="no"||this.isAsync==false){
       if(nodestatus=="closed"){
        childobj.src=this.img_nodenotclick;                  
       }
       else{
        childobj.src=this.img_nodeisclick;
       }              
     } 
    }
    else{
      if(nodestatus=="closed"){
       /*如果是最近一次点击的节点*/          
       if(nodeid==this.currentNodeID){
        childobj.src=this.img_selnode; 
       }
       else{
        childobj.src=this.img_node;
       }
      }
      else{
       if(childobj.imgtype=='node'){
         /*如果是最近一次点击的节点*/ 
         if(nodeid==this.currentNodeID){
         childobj.src=this.img_selopennode; 
         }
         else{
        childobj.src=this.img_opennode;
         }
       }
     }      
    } 
    }  
    }
    }
    //设置节点状态
   if(node.getState()=='closed')
   node.setState('open');
   else
   node.setState('closed');
 },

 /*设置点击时对应图标变化,标识当前节点
  *主要实现功能点:
  * 1、更新上次点击的节点的点击图片,如果是枝节点需要根据其状态选择更新的图片
  * 2、设置当前点击的节点的点击图片,如果是枝节点需要根据其状态选择更新的图片
  * 3、更新系统最近点击的节点类型、节点id
  */
 nameClick:function(src,objID){
    var obj=src;
    var parNode= obj.parentNode;
    var childobj="";
    var lastobj=""
    var lastNode=null;
    var node=this.getNode(objID);
    if(node.getURL()=='')
    return;
    /*取消上次点击的图片*/  
    if(this.currentNodeID!=""){
    lastobj=document.getElementById(this.currentNodeID);
    lastNode=this.getNode(tree.currentNodeID);
    for(i=0;i<lastobj.childNodes.length;i++){
     childobj = lastobj.childNodes[i];
     if(childobj.tagName!=null){
      if(childobj.tagName.toUpperCase()=="IMG" && childobj.imgtype=='node'){
      if(lastNode.getNodeType()=="leaf"){
       childobj.src=this.img_leaf;   
      }
      if(lastNode.getNodeType()=="node"){
      if(lastNode.getState()=="open"){
       childobj.src=this.img_opennode;  
      }
      else{
         childobj.src=this.img_node;
      }
      }            
      }
     }
    }
    }
    this.currentNodeID=parNode.id;
    for(i=parNode.childNodes.length;i>0;i--){
  childobj = parNode.childNodes[i];
  if(childobj!=null){
   if(childobj.tagName!=null){           
    if(childobj.tagName.toUpperCase()=="IMG" && childobj.imgtype=='node'){
       /*点击的为枝节点*/ 
       if(node.getNodeType()=="node") {
        if(node.getState()=="closed"){
         childobj.src=this.img_selnode;
        }
        else{
         childobj.src=this.img_selopennode;
        }
       }
       /*点击的为叶节点*/
       if(node.getNodeType()=="leaf"){
        this.lastclicktype= childobj.imgtype;
        childobj.src=this.img_selleaf;             
     }
     
    }
    
   }
  }
    }
    this.onClick(node);
 }
}

下面就来看看一颗树的例子
<html>
<head> 
  <script language="javascript">
  var tree=new Tree("tree");
  //点击节点
  function treeClick(node){
   alert('节点名称:'+node.getName()+'/n节点类型:'+node.getNodeType()+'/n节点级别:'+node.getLevel()+'/n节点URL:'+node.getURL());
   if(node.getParent()!=null)
   alert('父节点名称:'+node.getParent().getName());
  }
  //增加节点
  function add(){
      if(tree.getNode('AC')!=null){
    alert('节点已经添加');
    return ;
   }
   var node1=new Node('AC','不认识','AAAAAAAA','open');
   var node= tree.getNode('A');
      node.addChildNode(node1);
   tree.repaint();
  }
  //删除节点
  function remove(){ 
      if(tree.getCurrentNode()==null)
      return;
   tree.removeNode(tree.getCurrentNode().getNodeID());
   tree.repaint();
  } 
  var rootNode=new Node('AA','我认识的人','http://www.baidd.com','open');
   var node1=new Node('A','同事','A','open');
  var nodeA1=new Node('AAA1','kuyuer','A','open');
  node1.addChildNode(nodeA1);
  var node2=new Node('B','同学','A','closed');
  var node3=new Node('B1','唐海荣','A','open');
   node2.addChildNode(node3);
   var rootNode1=new Node('aaaa1','我的老师','http://www.baidu.com','closed');
  var node11=new Node('CCCC','陈阿梦','http://www.china.com','open');
  var node21=new Node('FFFF','陈天霸','A','open');
  rootNode.addChildNode(node1);
  rootNode.addChildNode(node2);
  rootNode1.addChildNode(node11);
  rootNode1.addChildNode(node21); 
   tree.addRoot(rootNode);  
 </script>
</head>
<body>
 <INPUT TYPE="button" value="增加节点" onclick="add()">
 <INPUT TYPE="button" value="删除节点"  onclick="remove()"><br><br>
 <script language="javascript">
   treeValue=tree.getTree();
  document.write(treeValue);
  //响应Tree的onClick的事件
  tree.onClick=treeClick; 
 </script>
</body>
</html>

原创粉丝点击