• 基于ajax的一个无限树型菜单【原创】


      最近又用到了树型菜单,原来做的是一次把数据都读出来,现在想想,感觉就是不爽,要是每次按需要读就ok了,正好可以用ajax。
      首先是ajax的处理,写个js吧,用oo写,ajax.js内容如下:

    /**
     * @author zxub 2006-06-01
     * 状态信息显示类,用var Status=new function()定义,可以静态引用其中的方法
     * 一般情况下为function Status(),这样不能静态引用其中的方法,需要通过对象来引用
     
    */
    var Status=new function()
    {
        
    this.statusDiv=null;
        
        
    /**
         * 初始化状态显示层
         
    */
        
    this.init=function()
        {
            
    if (this.statusDiv!=null)
            {
                
    return;
            }
            
    var body = document.getElementsByTagName("body")[0];
            
    var div = document.createElement("div");
            div.style.position 
    = "absolute";
            div.style.top 
    = "50%";
            div.style.left 
    = "50%";
            div.style.width 
    = "280px";
            div.style.margin 
    = "-50px 0 0 -100px";        
            div.style.padding 
    = "15px";
            div.style.backgroundColor 
    = "#353555";
            div.style.border 
    = "1px solid #CFCFFF";
            div.style.color 
    = "#CFCFFF";
            div.style.fontSize 
    = "14px";
            div.style.textAlign 
    = "center";
            div.id 
    = "status";
            body.appendChild(div);
            div.style.display
    ="none";
            
    this.statusDiv=document.getElementById("status");
        }
        
        
    /**
         * 设置状态信息
         * @param _message:要显示的信息
         
    */    
        
    this.showInfo=function(_message)
        {      
            
    if (this.statusDiv==null)
            {
                
    this.init();
            }  
            
    this.setStatusShow(true);
            
    this.statusDiv.innerHTML = _message;        
        }
         
        
    /**
         * 设置状态层是否显示
         * @param _show:boolean值,true为显示,false为不显示
         
    */ 
        
    this.setStatusShow=function(_show)
        {      
            
    if (this.statusDiv==null)
            {
                
    this.init();
            } 
            
    if (_show)
            {
                
    this.statusDiv.style.display="";
            }
            
    else
            {
                
    this.statusDiv.innerHTML="";
                
    this.statusDiv.style.display="none";
            }
        }
    }

    /**
     * @author zxub
     * 用于存放通道名称及通信对象的类,这样可以通过不同通道名称来区分不同的通信对象
     
    */
    function HttpRequestObject()
    {
        
    this.chunnel=null;
        
    this.instance=null;
    }

    /**
     * @author zxub
     * 通信处理类,可以静态引用其中的方法
     
    */
    var Request=new function()
    {
        
    this.showStatus=true;
        
        
    //通信类的缓存
        this.httpRequestCache=new Array();
        
        
    /**
         * 创建新的通信对象
         * @return 一个新的通信对象
         
    */
        
    this.createInstance=function()
        {
            
    var instance=null;
            
    if (window.XMLHttpRequest)
            {
                
    //mozilla
                instance=new XMLHttpRequest();
                
    //有些版本的Mozilla浏览器处理服务器返回的未包含XML mime-type头部信息的内容时会出错。因此,要确保返回的内容包含text/xml信息
                if (instance.overrideMimeType)
                {
                    instance.overrideMimeType
    ="text/xml";
                }
            }
            
    else if (window.ActiveXObject)
            {
                
    //IE
                var MSXML = ['MSXML2.XMLHTTP.5.0', 'Microsoft.XMLHTTP', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP'];
                
    for(var i = 0; i < MSXML.length; i++)
                {
                    
    try
                    {
                        instance 
    = new ActiveXObject(MSXML[i]);
                        
    break;
                    }
                    
    catch(e)
                    {                    
                    }
                }
            }
            
    return instance;
        }
        
        
    /**
         * 获取一个通信对象
         * 若没指定通道名称,则默认通道名为"default"
         * 若缓存中不存在需要的通信类,则创建一个,同时放入通信类缓存中
         * @param _chunnel:通道名称,若不存在此参数,则默认为"default"
         * @return 一个通信对象,其存放于通信类缓存中
         
    */
        
    this.getInstance=function(_chunnel)
        {
            
    var instance=null;
            
    var object=null;
            
    if (_chunnel==undefined)//没指定通道名称
            {
                _chunnel
    ="default";
            }
            
    var getOne=false;
            
    for(var i=0; i<this.httpRequestCache; i++)
            {
                object
    =HttpRequestObject(this.httpRequestCache[i]);
                
    if (object.chunnel==_chunnel)
                {
                    
    if (object.instance.readyState==0 || object.instance.readyState==4)
                    {
                        instance
    =object.instance;
                    }
                    getOne
    =true;
                    
    break;                    
                }
            }
            
    if (!getOne) //对象不在缓存中,则创建
            {
                object
    =new HttpRequestObject();
                object.chunnel
    =_chunnel;
                object.instance
    =this.createInstance();
                
    this.httpRequestCache.push(object);
                instance
    =object.instance;
            }         
            
    return instance;
        }
        
        
    /**
         * 客户端向服务端发送请求
         * @param _url:请求目的
         * @param _data:要发送的数据
         * @param _processRequest:用于处理返回结果的函数,其定义可以在别的地方,需要有一个参数,即要处理的通信对象
         * @param _chunnel:通道名称,默认为"default"
         * @param _asynchronous:是否异步处理,默认为true,即异步处理
         
    */
        
    this.send=function(_url,_data,_processRequest,_chunnel,_asynchronous)
        {
            
    if (_url.length==0 || _url.indexOf("?")==0)
            {
                Status.showInfo(
    "由于目的为空,请求失败,请检查!");
                window.setTimeout(
    "Status.setStatusShow(false)",3000);
                
    return;
            }
            
    if (this.showStatus)
            {
                Status.showInfo(
    "请求处理中,请稍候");  
            }  
            
    if (_chunnel==undefined || _chunnel=="")
            {
                _chunnel
    ="default";
            }
            
    if (_asynchronous==undefined)
            {
                _asynchronous
    =true;
            }
            
    try{
            
    var instance=this.getInstance(_chunnel);}catch(e){alert(e.message);}
            
    if (instance==null)
            {
                Status.showInfo(
    "浏览器不支持ajax,请检查!")
                window.setTimeout(
    "Status.setStatusShow(false)",3000);
                
    return;
            }        
            
    if (typeof(_processRequest)=="function")
            {
                instance.onreadystatechange
    =function()
                {
                    
    if (instance.readyState == 4// 判断对象状态
                    {
                        
    if (instance.status == 200// 信息已经成功返回,开始处理信息
                        {                        
                            _processRequest(instance);
                            Status.setStatusShow(
    false);
                            Request.showStatus
    =true;                                    
                        }
                        
    else
                        {
                            Status.showInfo(
    "您所请求的页面有异常,请检查!");
                            window.setTimeout(
    "Status.setStatusShow(false)",3000);
                        }                    
                    }                                
                }            
            }
            
    //_url加一个时刻改变的参数,防止由于被浏览器缓存后同样的请求不向服务器发送请求
            if (_url.indexOf("?")!=-1)
            {
                _url
    +="&requestTime="+(new Date()).getTime();
            }
            
    else
            {
                _url
    +="?requestTime="+(new Date()).getTime();
            }
            
    if (_data.length==0)
            {
                instance.open(
    "GET",_url,_asynchronous);
                instance.send(
    null);
            }
            
    else
            {
                instance.open(
    "POST",_url,_asynchronous);
                instance.setRequestHeader(
    "Content-Length",_data.length);
                instance.setRequestHeader(
    "Content-Type","application/x-www-form-urlencoded");
                instance.send(_data);
            }
        }
        
        
    /**
         * 间隔一段时间持续发送请求,只用于异步处理,只用于GET方式
         * @param _interval:请求间隔,以毫秒计
         * @param _url:请求地址
         * @param _processRequest:用于处理返回结果的函数,其定义可以在别的地方,需要有一个参数,即要处理的通信对象
         * @param _chunnel:通道名称,默认为"defaultInterval",非必添
         
    */
        
    this.intervalSend=function(_interval,_url,_processRequest,_chunnel)
        {
            
    var action=function()
            {
                
    if (_chunnel==undefined)
                {
                    _chunnel
    ="defaultInterval";
                }
                
    var instance=Request.getInstance(_chunnel);
                
    if (instance==null)
                {
                    Status.showInfo(
    "浏览器不支持ajax,请检查!")
                    window.setTimeout(
    "Status.setStatusShow(false)",3000);
                    
    return;
                }
                
    if (typeof(_processRequest)=="function")
                {
                    instance.onreadystatechange
    =function()
                    {
                        
    if (instance.readyState == 4// 判断对象状态
                        {
                            
    if (instance.status == 200// 信息已经成功返回,开始处理信息
                            {
                                _processRequest(instance);
                            }
                            
    else
                            {
                                Status.showInfo(
    "您所请求的页面有异常,请检查!");
                                window.setTimeout(
    "Status.setStatusShow(false)",3000);
                            }
                        }
                    }
                }
                
    //_url加一个时刻改变的参数,防止由于被浏览器缓存后同样的请求不向服务器发送请求
                if (_url.indexOf("?")!=-1)
                {
                    _url
    +="&requestTime="+(new Date()).getTime();
                }
                
    else
                {
                    _url
    +="?requestTime="+(new Date()).getTime();
                }
                instance.open(
    "GET",_url,true);
                instance.send(
    null);
            }
            window.setInterval(action,_interval);        
        }
    }


      然后就是读取数据生成菜单的treeMenu.js:

    /**
     * 树形菜单控制类
     * @author zxub
     
    */
    var TreeMenu=new function()
    {   
        
    this._url=null;
        
        
    //加入样式
        document.write('<style type="text/css">');
        document.write('.treeCheckBox{height:11px; 11px;vertical
    -align:middle}');
        document.write('.treeImg{cursor:pointer;vertical
    -align:text-bottom;margin-right:2px}');
        document.write('
    </style>');
        
        
    //定义图标显示用数组
        this.icon=new Array();
        
    this.icon["member"]='img/child.gif';
        
    this.icon["open"]='img/opened.gif';
        
    this.icon["close"]='img/closed.gif';    
         
        
    /**
         * 获取指定节点的子节点
         * @param _parentId:指定节点的id
         
    */ 
        
    this.getChildren=function(_parentId)
        {
            
    if (this.alreadyGetChileren(_parentId))
            {
                
    var childContainer=document.getElementById(_parentId+"_subContainer");
                
    if (childContainer)
                {
                    childContainer.style.display
    =(childContainer.style.display=="none")?"":"none";
                    
    var _parentNode=document.getElementById(_parentId);
                    
    if (_parentNode.firstChild && _parentNode.firstChild.tagName=="IMG")
                    {
                        _parentNode.firstChild.src
    =(childContainer.style.display=="none")?this.icon["close"]:this.icon["open"];
                    }
                }
                
    return;
            }
            
    var processRequest=function(obj)
            {
                TreeMenu.addChildren(_parentId,obj.responseXML);           
            }
            Request.send(
    this._url+"?pId="+_parentId,"",processRequest,_parentId+"");            
        }    
        
        
    /**
         * 根据获取的数据,设置指定节点的子节点
         * @param _parentId:指定节点id
         * @param _data:获取的数据
         
    */
        
    this.addChildren=function(_parentId,_data)
        {   
            
    if (this.alreadyGetChileren(_parentId))
            {         
                
    return;
            }
            
            
    var _parentNode=document.getElementById(_parentId);
            
    if (_parentNode.firstChild && _parentNode.firstChild.tagName=="IMG")
            {
                _parentNode.firstChild.src
    =this.icon["open"];
            }                     
            
    //子级容器,所有子级选项都放一个容器中
            _nodeContainer=document.createElement("div");
            _nodeContainer.id
    =_parentId+"_subContainer";
            
    //子级容器放入父级容器
            _parentNode.appendChild(_nodeContainer);
            
    var _children=_data.getElementsByTagName("root")[0].childNodes;
            
    var _child=null;
            
    var _point=this;
            
    for(var i=0; i<_children.length; i++)
            {
                _child
    =_children[i];                
                _node
    =document.createElement("div");
                
    if (i!=_children.length-1)
                {
                    _node.style.cssText
    ="padding-bottom:5px";
                }            
                _node.innerHTML
    ="";
                _node.id
    =_child.getAttribute("id");            
                
    //若节点存在下级节点
                if (_child.getAttribute("hasChildren")=="1")
                {
                    _node.innerHTML
    +='<img class="treeImg" onclick="TreeMenu.getChildren('+_child.getAttribute("id")+')" src="'+this.icon["close"]+'"/>';
                    _node.innerHTML
    +='<span style="cursor:pointer;line-height:16px;height:16px" name="treeText" onclick="treeNodeChoosed(this);">'+_child.firstChild.data+'</span>';                
                }
                
    //否则节点不存在下级节点
                else if (_child.getAttribute("hasChildren")==0)
                {
                    _node.innerHTML
    +='<img class="treeImg" onclick="try{treeNodeChoosed(this.nextSibling);}catch(e){alert(e.message);}" src="'+this.icon["member"]+'" style="margin-left:14px"/>';
                    _node.innerHTML
    +='<span style="cursor:pointer;line-height:16px;height:16px" name="treeText" onclick="treeNodeChoosed(this);">'+_child.firstChild.data+'</span>';                
                }
                
    //节点加入子级容器
                _nodeContainer.appendChild(_node);                        
            }
            _nodeContainer.style.cssText
    ="border-left:0px solid #ccc;margin-left:7px;margin-top:5px;padding-left:10px";        
        }
        
        
    /**
         * 判断指定节点是否已经获取子节点
         * @param _nodeId 指定节点id
         * @return [boolean]true为已经获取,false为未获取
         
    */
        
    this.alreadyGetChileren=function(_nodeId)
        {
            
    var obj=document.getElementById(_nodeId+"_subContainer");
            
    if (obj)
            {           
                
    return true;               
            }
            
    return false;        
        }    
    }

    /**
     * 点击菜单后的动作
     
    */
    function treeNodeChoosed(_obj)
    {
        
    var choosedColor="lightblue";
        
    var unChoosedColor="white";
        
        
    if (_obj.style.backgroundColor==choosedColor)
        {
            _obj.style.backgroundColor
    =unChoosedColor;           
        }
        
    else
        {
            
    //var allNodeText=document.getElementsByName("treeText");
            var allNodeText=document.getElementsByTagName("SPAN");
            
    for (var i=0; i<allNodeText.length; i++)
            {
                allNodeText[i].style.backgroundColor
    =unChoosedColor;
            }
            _obj.style.backgroundColor
    =choosedColor;
        }    
    }

      服务端返回的是xml,用responseText的话中文问题烦了,就用了xml,xml形如:

    <?xml version="1.0" encoding="UTF-8"?>
    <root>
     
    <node id="1" hasChildren="1">测试节点1</node>
     
    <node id="2" hasChildren="0">测试节点2</node>
    </root>

      表示的是所选取节点的子节点,id就是其在数据库中的id,hasChildren表示其是否有下级节点,至于其它什么属性可以按自己的需要加,然后,在生成树的js里加上相应的东东就可以了。
      我测试用的是asp,asp方便嘛,test2.asp代码如下:

    <%@LANGUAGE="JAVASCRIPT" CODEPAGE="65001"%>
    <%
        Response.ContentType
    ="text/xml";
        
    var xmlString='<?xml version="1.0" encoding="UTF-8"?>';
        xmlString
    +='<root>';
        
    if (Request.QueryString("pId")=="0")
        {
            xmlString
    +='<node id="1" hasChildren="1">测试类别1</node>';
        }
        
    else if (Request.QueryString("pId")=="1")
        {
            xmlString
    +='<node id="2" hasChildren="1">测试类别2</node>';
            xmlString
    +='<node id="4" hasChildren="0">测试类别4</node>';
            xmlString
    +='<node id="5" hasChildren="1">测试类别5</node>';
        }
        
    else if (Request.QueryString("pId")=="2")
        {
            xmlString
    +='<node id="6" hasChildren="1">测试类别6</node>';
            xmlString
    +='<node id="3" hasChildren="0">测试类别3</node>';
        }
        xmlString
    +='</root>';
        Response.write(xmlString);
    %>
      测试页面代码如下(test.htm):
    <html>
    <head>
    <title>测试</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    
    <script language="javascript" src="js/ajax.js"></script>
    <script language="javascript" src="js/treeMenu.js"></script>
    <style type="text/css">
    <!--
    body 
    { font-size: 12px;}
    -->
    </style>
    </head>
    <body>
    <href="javascript:TreeMenu.getChildren('0');">显示类别</a>
    <href="javascript:Request.intervalSend(3000,'test2.asp?pId=1',processRequest);">定时请求测试</a>
    <div id="0"></div>
    <script>
    TreeMenu._url
    ="test2.asp";
    var processRequest=function(obj)
    {
        alert(obj.responseText);
    }
    </script>    
    </body>
    </html>
      截图如下:
         
      文件打包下载:下载
  • 相关阅读:
    USACO2.24 Party Lamps
    hdu3811 Permutation
    局部视图Partial
    动态修改a标签的css样式
    .net 记住用户名和密码
    C#枚举
    学习存储过程的时候参看的两个DVBBS的存储过程和两个初步了解后自己写的存储过程(带分页的)
    js 几种常用的表单输入判断
    AJAX+.net实现无刷新搜索,无须提交,边输边查
    ifream中的数据传递
  • 原文地址:https://www.cnblogs.com/zxub/p/403399.html
Copyright © 2020-2023  润新知