zoukankan      html  css  js  c++  java
  • 无限树形选择菜单类【原创】

      前两天想把无限联动改成颗树,好选择嘛,所以就写了点东西。
      所需数据sortArr.js,每项最后一位表示是组还是元素:
    var arrSorts = new Array(35);
    arrSorts[0] = [1, "主类别一1", "0","0"];
    arrSorts[1] = [2, "主类别二2", "0","0"];
    arrSorts[2] = [3, "主类别三3", "0","1"];
    arrSorts[3] = [4, "小类一4", "1","0"];
    arrSorts[4] = [5, "小类二5", "1","0"];
    arrSorts[5] = [6, "小类三6", "1","1"];
    arrSorts[6] = [7, "细类一7", "4","0"];
    arrSorts[7] = [8, "细类二8", "4","0"];
    arrSorts[8] = [9, "细类三9", "4","1"];
    arrSorts[9] = [10, "小类四10", "2","1"];
    arrSorts[10] = [11, "小类五11", "2","1"];
    arrSorts[11] = [12, "小类六12", "2","1"];
    arrSorts[12] = [13, "细类四13", "5","1"];
    arrSorts[13] = [14, "细类五14", "5","1"];
    arrSorts[14] = [15, "末类一15", "7","0"];
    arrSorts[15] = [16, "末类二16", "7","0"];
    arrSorts[16] = [17, "末类三17", "7","0"];
    arrSorts[17] = [18, "终极类一18", "15","1"];
    arrSorts[18] = [19, "终极类二19", "15","1"];
    arrSorts[19] = [20, "终极类三20", "15","1"];
    arrSorts[20] = [21, "终极类四21", "16","1"];
    arrSorts[21] = [22, "终极类五22", "16","1"];
    arrSorts[22] = [23, "终极类六23", "16","1"];
    arrSorts[23] = [24, "末类四24", "8","0"];
    arrSorts[24] = [25, "末类五25", "8","1"];
    arrSorts[25] = [26, "末类六26", "8","1"];
    arrSorts[26] = [27, "末类七27", "9","0"];
    arrSorts[27] = [28, "末类八28", "9","0"];
    arrSorts[28] = [29, "末类九29", "9","0"];
    arrSorts[29] = [30, "终极类七30", "17","1"];
    arrSorts[30] = [31, "终极类八31", "17","1"];
    arrSorts[31] = [32, "终极类九32", "17","1"];
    arrSorts[32] = [33, "终极类十33", "24","1"];
    arrSorts[33] = [34, "终极类十一34", "24","1"];
    arrSorts[34] = [35, "终极类十二35", "24","1"];
    arrSorts[35] = [36, "终极类十三36", "24","1"];

      主要类tree.js:
    /**
     * 无限树形选择菜单类
     * _containerName:显示该菜单的容器元素名称
     * _dataArr:显示菜单所需的数组,格式如下
     * 节点类型用于判断该节点是组还是成员
     * arrSorts[0] = ["类别ID1", "类别一", "父类ID1","节点类型1"];
     * arrSorts[1] = ["类别ID2", "类别二", "父类ID2","节点类型2"];
     * 数组元素的第一项类别ID的数据类型与数据库中的一样,若为数字,则不加引号
     * @author zxub 2005-10-09
     */
    function tree(_containerName,_dataArr)

        //加入样式
        document.write('<style type="text/css">');
        document.write('.treeCheckBox{height:11px; 11px;vertical-align:middle}');
        document.write('.treeImg{cursor:hand;vertical-align:text-bottom;margin-right:2px}');   
        document.write('</style>');
       
        //定义图标显示用数组
     this.icon=new Array();
     this.icon["member"]='img/member.gif';
     this.icon["open"]='img/open.gif';
     this.icon["close"]='img/close.gif';
     /*this.icon["jointop"]='img/jointop.gif';
     this.icon["joinmiddle"]='img/joinmiddle.gif';
     this.icon["joinbottom"]='img/L.gif';
     this.icon["plustop"]='img/plustop.gif';
     this.icon["plusmiddle"]='img/plusmiddle.gif';
     this.icon["plusbottom"]='img/plusbottom.gif';
     this.icon["minustop"]='img/minustop.gif';
     this.icon["minusmiddle"]='img/minusmiddle.gif';
     this.icon["minusbottom"]='img/minusbottom.gif';
     this.icon["line"]='img/line.gif';*/  
     
     //获取树结构所需父容器和数据
     this.container=document.getElementById(_containerName);
     this.dataArr=_dataArr;
     
     //定义区分组和成员所用的值
     this.groupValue=0;
     this.memberValue=1;
     
     /**
      * 根据所取节点ID和子级所存放容器,生成该节点的下级选项
      * _parentId:所取节点ID,对于子级选项来说,它是parentID。
      * _container:用来存放子级选项的容器。
      */
     this.setNode=function(_parentId,_container)
     {
      var length=this.dataArr.length;
      //设置一个标记,若为false,说明没子级,则要删除自己容器。
      var getChild=false;
      //子级容器,所有子级选项都放一个容器中。
      _nodeContainer=document.createElement("div");
      _nodeContainer.id="_container"+_parentId;
      //子级容器放入选项存放容器
      _container.insertAdjacentElement("beforeEnd",_nodeContainer);
      //遍历数组,获取子级
      for (var i=0;i<length;i++)
      {
       if (this.dataArr[i][2] == _parentId)
       {
           getChild=true;
        _node=document.createElement("div");
        _node.style.cssText="padding-bottom:5px";
        _node.innerHTML="";  
        //若所取为组         
        if (this.dataArr[i][3]==this.groupValue)
        {
            _node.innerHTML+='<input onFocus="this.blur()" onclick="setChildrenChecked(this);setParentChecked(this)" type="checkbox" class="treeCheckBox" name="group" id="'+this.dataArr[i][0]+'">';
            //_node.innerHTML+='<img style="cursor:hand" src="'+this.icon["plusmiddle"]+'"/>';
         _node.innerHTML+='<img class="treeImg" src="'+this.icon["close"]+'" onclick="changeShowStatus(this,this.parentNode.lastChild);"/>';     
         _node.innerHTML+='<span style="cursor:hand" onclick="this.previousSibling.click();">'+this.dataArr[i][1]+'</span>';
        }
        //否则若所取为成员
        else if (this.dataArr[i][3]==this.memberValue)
        {
            _node.innerHTML+='<input onFocus="this.blur()" onclick="setParentChecked(this);" type="checkbox" class="treeCheckBox" name="member" id="'+this.dataArr[i][0]+'">';
         //_node.innerHTML+='<img style="cursor:hand" src="'+this.icon["plusmiddle"]+'"/>';
         _node.innerHTML+='<img class="treeImg" src="'+this.icon["member"]+'"/>';     
         _node.innerHTML+='<span style="cursor:hand" onclick="this.parentNode.firstChild.click();">'+this.dataArr[i][1]+'</span>';
        }
        //节点加入子级容器
        _nodeContainer.insertAdjacentElement("beforeEnd",_node);    
       }   
      }
      if (_parentId==this.dataArr[0][2])
      {
          _nodeContainer.style.cssText="margin-top:5px";
      }
      else
      {
          _nodeContainer.style.cssText="display:none;margin-left:18px;margin-top:5px";
      }
      //若没有子级,则删除子级容器
      if (getChild==false)
      {
          _container.removeChild(_nodeContainer);
      }
     } 
     
     /**
      * 获取一个容器中的所有子级对象(只是子级)
      * _container:容器对象
      */
     this.getChildren=function(_container)
     {
      var _children=_container.children;  
      return _children;  
     } 
     
     /**
      * 根据容器中的选项,生成树结构
      * _container:所取容器对象
      */
     this.setTree=function(_container)
     {
         //获取容器中所有对象
      var _root=this.getChildren(_container);
      var length=_root.length;
      //遍历容器中的对象
      for (var i=0;i<length;i++)
      {
          //生成子级选项
       this.setNode(_root[i].firstChild.id,_root[i]);
       //递归完成整颗树   
       this.setTree(_root[i].lastChild);
      }
     }
     
     //由于数组中数据的规则,第一个节点的父级节点必是其它节点的父级节点
     //数组规则不再缀述,可参考无限分类所用数组介绍
     //下面二句把整颗完整的树构造出来
     this.setNode(this.dataArr[0][2],this.container); 
     this.setTree(this.container.firstChild);
    }

    /**
     * 单击复选框后,图片变换处理
     * obj复选框对象
     */
    function changePic(obj)
    {
     obj.checked=(obj.checked==true?false:true);
     //复选框的下一个兄弟对象则是图片
     obj.nextSibling.src=(obj.checked==true?"img/open.gif":"img/close.gif");
     //设置下级复选框的选择情况
     setChildChecked(obj); 
    }

    /**
     * 改变下级选项的显示/隐藏,同时,改变图片的显示
     * _pic:要改变的图片对象
     * _div:要改变的选项容器对象
     */
    function changeShowStatus(_pic,_div)
    {
        if (_div.tagName=="DIV")
        {
            _div.style.display=(_div.style.display=="none")?"":"none";
            _pic.src=(_div.style.display=="none")?"img/close.gif":"img/open.gif";
        }   
    }

    /**
     * 设置下级选项复选框的选择情况
     * _obj:上级选项对应的复选框对象
     */
    function setChildrenChecked(_obj)
    {
     var _checked=_obj.checked;
     var _siblingDiv=_obj.parentNode.lastChild;
     if (_siblingDiv.tagName=="DIV")
     {
         var _children=_siblingDiv.children;
         var length=_children.length;
         for (var i=0;i<length;i++)
         {
             _children[i].firstChild.checked=_checked;
             setChildrenChecked(_children[i].firstChild);
         }
     }
    }

    /**
     * 设置上级选项的选择情况
     * _obj:选项所对应的复选框对象
     */
    function setParentChecked(_obj)
    {
        //只有取消复选框选择时,父级选项的选择才要取消
        if (_obj.checked==false)
        {    
            //获取父级选项对应的复选框  
            var _parentCheckBox=_obj.parentNode.parentNode.parentNode.firstChild;
            if (_parentCheckBox && _parentCheckBox.tagName=="INPUT" && _parentCheckBox.type=="checkbox")
            {
                _parentCheckBox.checked=false;
                setParentChecked(_parentCheckBox);
            }
        }   
    }

    /**
     * childId和parentId对应的对象是否存在父子关系
     * arr:所用数组
     * 由于数组的特殊结构,做为子级的选项的id必然要大于父级选项的id
     */
    function checkChild(childId,parentId,arr)
    {
     var returnValue=false;
     var length=arr.length;
     var pid=0;
     for (i=0;i<length;i++)
     {
      if (arr[i][0]==childId)
      {
       pid=arr[i][2];
       break;
      }
      else if (arr[i][0]>childId)
      {
       break; 
      }
     }
     //父级可能与parentId对应对象存在父子关系,故递归判断
     if (pid>parentId)
     {
      returnValue=checkChild(pid,parentId,arr);
     }
     else if (pid==parentId)
     {  
      returnValue=true;
     }
     return returnValue;
    }

    /**
     * 获取页面一组Name一样的复选框选中项的值集合
     * _groupName:组对象的名称
     */
    function getGroupChoosed(_groupName)
    {
     var chooseValue=new Array;
     var member=document.getElementsByName(_groupName);
     var length=member.length;
     for (var i=0;i<length;i++)
     {
         if (member[i].checked==true)
         {
             chooseValue.push(member[i].id);
         }
     }
     return chooseValue;
    }
      测试页面test.htm:
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <HTML>
    <HEAD>
    <TITLE> New Document </TITLE>
    <META NAME="Generator" CONTENT="EditPlus">
    <META NAME="Author" CONTENT="">
    <META NAME="Keywords" CONTENT="">
    <META NAME="Description" CONTENT="">
    <script language="javascript" src="sortArr.js"></script>
    <script language="javascript" src="tree.js"></script>
    <style type="text/css">
    <!--
    body { font-size: 12px;}
    -->
    </style>
    <!--div { border: 1px solid black; padding: 5px}-->
    </HEAD>

    <BODY>
    <P id=selBox></P>
    <script language="javascript">
     var b=new tree("selBox",arrSorts);
    </script>
    <INPUT TYPE="button" value="测试父子关系" onclick="alert(checkChild(23,1,arrSorts))">
    <input id="tt" size="100">
    <INPUT TYPE="button" value="获取选择成员" onclick="tt.value=getGroupChoosed('member')">
    </BODY>
    </HTML>
      效果类似windows资源管理器,多了复选框。
      今天就写到这里了,还有些东西太大了,代码太多,下次有空再贴上来吧。

  • 相关阅读:
    Windows进程/线程创建过程
    固件安全研究
    区块链安全研究的总结
    CoTreatAsClass一些注意事项
    Ring3 读取SSDT
    User Mode Scheduling
    首次异常和二次异常
    offer终于有着落了
    AtomBombing
    Retn
  • 原文地址:https://www.cnblogs.com/zxub/p/253464.html
Copyright © 2011-2022 走看看