为什么非要源代码?
思路:
1、每个树枝关心它的parent和item集合,找到层次关系
2、找你喜欢的方法来构建实体,如<li>,<div>,<table>都可以不过最好不要用table,它比较麻烦
3、使用js生成代码,这样可以保证你的树随时添枝加叶,当让也就能根据数据库变化了。
这是我的风格,最重要的是找到逻辑关系,逻辑关系定了,如很生成html代码就非常简单了。

解决方案 »

  1.   

    我搜索了,没找到呀。我所要做的菜单是结合数据库权限和layer的且要收回某些子菜单项所占据的 layer空间
      

  2.   

    下面是我认为最简单的树了,那么你所要做的就是是用js 生成html代码,给每个元素起一个名字,不用sourceIndex+1这种方式,作协扩展,是她能够在任何时候在预期的位置生成树枝,或删除树枝,
    <html>
    <head>
    <title>Left</title>
    <link rel="stylesheet" href="css/css.css" type="text/css">
    <style>
    <!--
    #foldheader{cursor:hand ;font-size: 10pt;
    list-style-image:url(plus1.gif)}
    #foldinglist{font-size: 10pt;list-style-image:url(min1.gif); margin-left: 11 px}
    //-->
    </style>
    <script language="JavaScript1.2">
    function change(){
    if(!document.all)
    return
    if (event.srcElement.id=="foldheader") {
    var srcIndex = event.srcElement.sourceIndex
    var nested = document.all[srcIndex+1]
    if (nested.style.display=="none") {
    nested.style.display=''
    event.srcElement.style.listStyleImage="url(min1.gif)"
    }
    else {
    nested.style.display="none"
    event.srcElement.style.listStyleImage="url(plus1.gif)"
    }
    }
    }
    document.onclick=change
    //-->
    </script>
    </head>
    <body bgcolor="#69e90a" text="#000000" leftmargin="30" topmargin="0">
    <nobr>
    <ul id="foldinglist">
      <li id="foldheader">公共信息</li>
      <ul id="foldinglist" style="display:none" >
           <li><a href="send.jsp?groupid=100" target="_top">公共信息</a></li>
           <li id="foldheader">kdk</li>
           <ul id="foldinglist" style="display:none" >
               <li><a href="send.jsp?groupid=101" target="_top">公共信息</a></li>
           </ul>
       </ul>
       <li id="foldheader">商学院</li>
       <ul id="foldinglist" style="display:none" >
             <li><a href="send.jsp?groupid=100" target="_top">公共信息</a></li>
             <li id="foldheader">kdk</li>
             <ul id="foldinglist" style="display:none" >
                  <li><a href="send.jsp?groupid=101" target="_top">公共信息</a></li>
              </ul>
        </ul>
    </ul>
    </nobr>
    </body>
    </html>
      

  3.   

    1.结合数据库权限收回某些子菜单项所占据的 layer空间
    ------------------------------------------------
    难道layer是先静态设计好,然后根据权限显示或隐藏?-----------------------------------------------
    2.菜单有几层?是outlook风格的两层菜单式还是无穷的树型菜单?问题不描述清楚,急有什么用^_^
      

  4.   

    用frameset。
    更改各个frame的宽度。
    试试吧,很简单的。
      

  5.   

    to sunbeamy(阳光灿烂的深夜) (  ):
    根据数据库变化了。
    级数不确定了,你有好办法吗?最好结构清楚,便于再利用。
    ---------------------------------------------------
    to Muzhu(思考在DHTML) :
    用frameset。
    更改各个frame的宽度。
    试试吧,很简单的。
    ---------------------
    具体怎么做?
    ------------------
    各位帮帮忙吧?
    星期一交差呀。救命呀!
      

  6.   

    如果你需要根据数据库变化的话,你值需要创建一个元素,<li>..</li><ul></ul>,当你点击li时把数据库对应的值存入数组,然后把数组中的值分别放到自己的<li>中,最后在点击的li对应的ul中加入所有刚才生成的html代码就可以了。当你关闭li时,删除数组中对应的元素,并且删除ul中的html就可以了。这样就可以做到,虽数据库内容变化而变化,这样实现比较容易,我曾经在本地做实验过,主要负荷仍旧是服务器,客户端只是做些简单负值操作,所以当你的数据较大时效率不是很低!
      

  7.   

    如果你需要根据数据库变化的话,你值需要创建一个元素,<li>..</li><ul></ul>,当你点击li时把数据库对应的值存入数组,然后把数组中的值分别放到自己的<li>中,最后在点击的li对应的ul中加入所有刚才生成的html代码就可以了。当你关闭li时,删除数组中对应的元素,并且删除ul中的html就可以了。这样就可以做到,虽数据库内容变化而变化,这样实现比较容易,我曾经在本地做实验过,主要负荷仍旧是服务器,客户端只是做些简单负值操作,所以当你的数据较大时效率不是很低!
      

  8.   

    当然如果你的数据库内容变化不象聊天信息那样随时变化,你没有必要删除数组中的内容,这样可以起到缓存作用,不使用display:none的方法,因为display这种方法实现的树依赖于html代码已经存在,动态改变树值很困难,尤其是当树比较复杂时,我说的这种方法的意思是不显示的就不存在,存在的只有数据(如果你没有删除树组),你可以结合一个隐藏的帧来不通过刷新页面来更新数据
      

  9.   

    to 百乐宝:我要的正是根据数据库中用户的权限来动态生成导航菜单。开始页面加载时是没有菜单的。
    但是我不知道怎样用代码从数据库取回?
    即怎样用JSP输出生成相应的菜单项,好象层之间的位置也很难定位呀(相对?绝对?)?
    而且头儿要求用DIV。你能告诉我吗?谢谢了!
      

  10.   

    我现在不会的地方是:怎样用代码从数据库取回用户的权限并动态的输出相应的HTML生成以DIV表示的菜单?谁能给出代码,立即放分!
    这个过程我一点也不会呀!
    星期一交差呀!可怜可怜吧!
      

  11.   

    呵呵,开发这个代码核心部分我一共用了 3 天,递归调用并生成显示用 html 代码很令人头疼的。而且也是根据权限来判断某项显与不显,层数不固定,而且是仿传统winapp应用置顶下拉菜单,然后用户权限设置页面也做的跟一般的安装程序要用哪个模块就在树状结构前面打勾,用起来很方便。系统是用 c#.net + odbc.net 开发的,后台数据库不固定。
      

  12.   

    现在准备重写这部分代码。核心算法是不会变,但数据输出我会使用 xml 数据岛的形式配合 xsl 来生成客户端的显示,以实现多种多样的变化
      

  13.   

    呵呵,一堆懒人。去找fktree.js嘛,模仿里面的示范HTML代码写jsp代码,把数据库的查询结果变成树就成了,也没有层数限制,不过节点太多了客户端运算压力会比较大。
    别人现成的代码不可能拿来就能用的,没有一模一样的需求啊,权限系统、数据库表结构也不一样,访问方式也不一样,怎么能抄呢?
      

  14.   

    sunbeamy(阳光灿烂的深夜):光说不练!谁给出代码。还有最后一天了。救命!
    今天晚上结帐!
    今天晚上结帐!
      

  15.   

    我写一个不过是用ASP写的。
    下面是我写的一个程序,因为觉得比较好,值得借鉴, 
    所以放了上来, 
    如果转载,请注明出自(不死鸟 QQ33054474) 
    谢谢 < !-- #include virtual='Include/database.asp' --> 
    < % 
    set rs=Server.CreateObject("ADODB.RecordSet") sql="SELECT menu_name, menu_link, menu_bgcolor, menu_color,id FROM enter_individual WHERE (parent_id = (SELECT id FROM enter_individual WHERE menu_flag = 'root' )) " '查询得到根节点 
    rs.Open sql,conn,1,1 
    Response.Write "< table width=100% border=0 cellspacing=1 cellpadding=0 align=center>< tr bgcolor=#3399CC valign=bottom align=center>" 
    sumnum=rs.RecordCount 
    myArray=rs.GetRows() 
    rs.Close () 
    widd=780/sumnum '从一级子菜单数目判断弹出菜单x坐标的递增像素 
    dim i 
    i=0 
    defaultbgcolor="#3399cc" '指定默认底色 
    defaultcolor="#ffffff" '指定默认字体颜色 
    defaultlink="#" '指定默认链接 
    posit_x=0 'x位置 
    flag=1 '标志,作为菜单弹出方向 1表示向右,0表示向左 
    'Response.Write myArray(4,6) 
    while i Response.Write "< td height=20 bgcolor="&myArray(2,i)&" width="&widd&">< a href="&myArray(1,i)&" onmouseover=java script:a"&myArray(4,i)&".style.display='block' onmouseout=java script:a"&myArray(4,i)&".style.display='none' >< font color="&myArray(3,i)&" >"&myArray(0,i)&"< /a>< /td>" 
    '----------------------------------------------- i=i+1 
    Wend 
    Response.Write "< /tr>< /table>" i=0 
    while i posit_y=100 'y位置回到原位 
    If i>=(sumnum/2) Then '如果菜单进入右半部分,则弹出转向 
    flag=0 
    End If '调用GetSubMenu 函数 设置该项一级菜单的下级菜单,以myArray(4,i) 即菜单id作为下级菜单所在div 的id GetSubMenu myArray(4,i),posit_x,posit_y 
    posit_x=posit_x+widd '下一个一级菜单的子菜单的 x坐标值增加一个单位 
    i=i+1 Wend '使用递规算法的到下级菜单的函数 
    'parent_id 父 id; posit_x 弹出层的左边位置; posit_y 弹出层的离上面位置; Function GetSubMenu(parent_id,posit_x,posit_y) 
    dim myArray 
    dim sumnum 
    dim i '查询子菜单的下级菜单 
    sql="SELECT menu_name, menu_link, menu_bgcolor, menu_color,id FROM enter_individual WHERE parent_id = "&parent_id&" AND user_id = '"&userid&"'" 
    rs.Open sql,conn,1,1 '如果下级菜单不存在,则层数减一 ,关闭数据库链接,建立一个以父id为div id的空层,然后返回 
    If rs.EOF=true Then 
    level=level-1 
    rs.Close () 
    'Response.Write parent_id 
    Response.Write "< div id='a"&parent_id&"' style='position: absolute; top: 4; left: -1; display: none; width: 0; height: 0'>< /div>" 
    Else '如果存在取到数据库数据,并调用SetSubMenu显示菜单 
    sumnum=rs.RecordCount 
    myArray=rs.GetRows() 
    rs.Close () 
    SetSubMenu myArray,sumnum,parent_id,posit_x,posit_y '对数据进行循环,递规调用GetSubMenu 
    i=0 
    while i< sumnum 
    posit_y=posit_y*1+20 '递规一次posit_y 加一个单位, 
    if level=0 Then '如果级数减到0 则回到1 
    level=1 
    End If 
    'If flag=1 Then 
    'GetSubMenu myArray(4,i),posit_x+level*widd,posit_y-level*20 '递规调用GetSubMenu x,y坐标延伸 level 个单位 
    'End If 
    If flag=0 Then 
    GetSubMenu myArray(4,i),posit_x-level*widd,posit_y-level*20 '递规调用GetSubMenu x,y坐标延伸 level 个单位 
    Else 
    GetSubMenu myArray(4,i),posit_x+level*widd,posit_y-level*20 '递规调用GetSubMenu x,y坐标延伸 level 个单位 
    End If i=i+1 
    Wend 
    End If End Function '设置子菜单函数 
    'myArray 菜单数据 ,sumnum 数组大小 ,parent_id 层的id ; 
    'posit_x 弹出层的左边位置; posit_y 弹出层的离上面位置; Function SetSubMenu (myArray,sumnum,parent_id,posit_x,posit_y) 
    dim i 
    parent_id="a"&parent_id '父菜单id前面加上a 作为层的id 
    hh=sumnum*20 '数组大小乘以20作为层的高度 
    Response.Write "< DIV onmouseover=java script:"&parent_id&".style.display='block' onmouseout=java script:"&parent_id&".style.display='none' ID='"&parent_id&"' STYLE='position: absolute; top:"&posit_y&"; left:"&posit_x&"; height:"&hh*1&"; width: "&widd&"; display:none;vertical-align: top'>< table width=100% border=0 cellspacing=1 cellpadding=0 >" 
    i=0 
    While i myArray(0,i)=Trim(myArray(0,i)) 
    myArray(1,i)=Trim(myArray(1,i)) 
    myArray(2,i)=Trim(myArray(2,i)) 
    myArray(3,i)=Trim(myArray(3,i)) 
    If myArray(2,i)="" Then 
    myArray(2,i)=defaultbgcolor 
    End If If myArray(3,i)="" Then 
    myArray(3,i)=defaultcolor 
    End If If myArray(1,i)="" Then 
    myArray(1,i)=defaultlink 
    End If 
    Response.Write "< tr align=center >< td width=100% height=20 bgcolor="&myArray(2,i)&" onmouseover=java script:"&parent_id&".style.display='block';a"&myArray(4,i)&".style.display='block' onmouseout=java script:a"&myArray(4,i)&".style.display='none'>< a href='"&myArray(1,i)&"'>< font color="&myArray(3,i)&" >"&myArray(0,i)&"< /font>< /a>< /td>< /tr>" i=i+1 
    Wend Response.Write " < /table> < /DIV>" 
    End Function Set rs=nothing 
    conn.Close () 
    Set conn=nothing 
    % >
      

  16.   

    拜托!请看清我问的问题再回答。我不会完全照抄你的代码的,我不会抢你的饭碗的,因为我只不过是一个小菜鸟而已!只是想参考参考我也找了几种菜单,但总是认为不太合适(从性能上,易用性上,reused上),好多方面都要考虑。
    我请大家贴上代码的目的是想参考对比一下各种解决方法的优劣,以便选择。只是想参考参考如果大家都把自己的代码贴上来互相讨论并借鉴提高不是很好的事吗?等到代码烂在脑子里吧?
      

  17.   

    我个人认为比较好的方法是
    在前台写一个用xml数据岛绑定的菜单组件(可以用htc)
    菜单的内容由xml数据决定
    这个你可以写一个java类通过权限来生成这段xml数据
    可以根据不同用户分别设置
    这种方案是可行的,我现在使用的就是这种方案
    效果很好
      

  18.   

    不好意思,现在才给你,我很忙,本来没有工作,现在又要找房子,麻烦得很。现在个你个动态生成树的例子,你可以用你的jsp生成客户端脚本,让她动态产生树枝,当然是jsp判断权限之后了。这个例子功能不全,你看完了就可以自己扩展功能。希望这对你有用!
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <HTML>
    <HEAD>
    <TITLE> tree view </TITLE>
    <META NAME="Generator" CONTENT="EditPlus">
    <META NAME="Author" CONTENT="">
    <META NAME="Keywords" CONTENT="">
    <META NAME="Description" CONTENT="">
    <style>
    <!--
    .header{cursor:hand ;font-size: 10pt;
    list-style-image:url(plus1.gif)}
    .list{font-size: 10pt;list-style-image:url(min1.gif); margin-left: 11 px;}
    .yellowSmallCLF { font-size: 11px; color: #000000;}
    .yellowSmallCLF   a:link     { color: #000000; text-decoration: none;}
    .yellowSmallCLF a:visited { color: #000000; text-decoration: none;}
    .yellowSmallCLF a:active { color: #000000; text-decoration: none;}
    .yellowSmallCLF a:hover     { color: #FF9900; text-decoration: underline;}
    //-->
    </style>
    <SCRIPT LANGUAGE="JavaScript">
    <!--
    /*------------------------ Class...  -----------------------------*/
    function TTreeView(name){
        this.name=name;
    this.database='';//extent...
        this.items=new Array();//TTreeNodes(this);
    this.items[this.items.length]=new TTreeNode(this,'topNode','','Top TreeNode');//
    this.items['topNode']=this.items[this.items.length-1];
        //method...
    this.create=create;
    this.add=add;
    this.trimData=trimData;
    this.showChild=showChild;
    }
    function TTreeNode(owner,name,parent,caption,action,img){
         this.owner=owner;
     this.name=name;
     this.parentName=parent;
     this.childs=new Array();
     this.caption=(!action?'':('<span class="yellowSmallCLF" ><a href="#" onclick="'+action+'">'))+caption+(!action?'':'</a></span>');
     this.action=action;
     this.img=img;
         this.index=owner.items.length;
     //method...
     this.addChild=addChild;
    }
    /*------------------------ Methods...  -----------------------------*/
    function add(name,parent,caption,action,img){
        this.items[this.items.length]=new TTreeNode(this,name,parent,caption,action,img);//
    this.items[name]=this.items[this.items.length-1];
    }
    function create(){
       this.trimData();
       document.write(this.items[0].htmlcode);
    }
    function trimData(){
       for(i=0;i<this.items.length;i++){
            var obj=this.items[i]
            var pn=obj.parentName;
    if(pn!=''){
       this.items[pn].childs[this.items[pn].childs.length]=obj;
       obj.htmlcode='<li id="'+this.name+'_'+obj.name+'" class="header">'+obj.caption+'</li><ul class="list" id="'+this.name+'_'+obj.name+'_child" style="display:none"></ul>';
    }else{
      obj.htmlcode='<ul class="list">\n<li id="'+this.name+'_topNode" class="header">'+obj.caption+'</li><ul class="list" id="'+this.name+'_'+obj.name+'_child" style="display:none"></ul></ul>';
    }
       }
       
    }
    function showChild(name){
      /*  var str='';
        for(i=0;i<this.items[name].childs.length;i++){
         str+=this.items[name].childs[i].htmlcode;
    }
    document.all['node_'+name+'_child'].innerHTML=str;
    alert(str)//document.all.node_topNode.innerHTML
    return false;*/
    }
    function getNameByIdstr(idstr){
        var beginnum=idstr.indexOf("_")+1;//异常处理!!!!!
    var name=idstr.slice(beginnum);
    return name;
    }
    function getOwnerByIdstr(idstr){
        var beginnum=idstr.indexOf("_");//异常处理!!!!!
    var name=idstr.substring(0,beginnum);
    return name;
    }
    function changeIt(){
           var idstr=window.event.srcElement.id;
       var n=getNameByIdstr(idstr);
       var str='';
       if(document.all[idstr+'_child'].innerHTML==''){
          var tree=eval(getOwnerByIdstr(idstr));
          for(i=0;i<tree.items[n].childs.length;i++)str+=tree.items[n].childs[i].htmlcode;
          if(tree.items[n].childs.length!=0){
          document.all[idstr+'_child'].innerHTML=str;
      document.all[idstr+'_child'].style.display="block";
      }
      document.all[idstr].style.listStyleImage="url(min1.gif)"
       }else{
          document.all[idstr+'_child'].innerHTML='';
      document.all[idstr+'_child'].style.display="none";
      document.all[idstr].style.listStyleImage="url(plus1.gif)"
       }
    }
    function addNode(){//这里可以动态的添加一个Node到指定的node上,这只是个演示,你应该把它扩展,并且符合面向对象的原则。
         var idstr=window.event.srcElement.id;
     var pn=getNameByIdstr(idstr);
     var tree=eval(getOwnerByIdstr(idstr));
     var name=pn+tree.items[pn].childs.length;
     var caption=prompt('请输入名字',name);
     var action=prompt('请输入动作','alert(3)');
     
     if(confirm('你确定要在这里添加一个Node')){
        tree.add(name,pn,caption,action)//,img)
            tree.items[name].htmlcode='<li id="'+tree.name+'_'+name+'" class="header">'+caption+'</li><ul class="list" id="'+tree.name+'_'+name+'_child" style="display:none"></ul>';
        tree.items[pn].childs[tree.items[pn].childs.length]=tree.items[name];
         }}
    function myClick(){
       try{//必须
           changeIt();
       }
       catch(x){}
    }
    function myDblClick(){
        try{//必须
           addNode();
       }
       catch(x){}
    }
    document.onclick=myClick;
    document.ondblclick=myDblClick
    /*----------------- 废弃的方法-----------------*/
    function del(name){
    }
    function addChild(){//用来动态填加node到name中,这里只给你一个粗糙的添加方法,
     /*var name=this.name+this.owner.items[this.name].childs.length;
    var caption=prompt('请输入名字',name);
    var action=prompt('请输入动作','alert(3)');
    this.owner.add(name,this.name,caption,action)//,img)
        this.owner.trimData();*/
    }
    //-->
    </SCRIPT>
    </HEAD><BODY>
    <SCRIPT LANGUAGE="JavaScript">
    <!--
    ot=new TTreeView('ot');
    ot.add('class','topNode','class');
      ot.add('H971','class','环化971班');
         ot.add('llrock','H971','llrock');
         ot.add('nickname','llrock','百乐宝','alert(30)');
         ot.add('bbrock','H971','bbrock');
      ot.add('H972','class','H972');
    ot.create();
    //ot.items[0].addChild()//-->
    </SCRIPT>
    <br><b>单击展开,双击在此节点添加一个子节点;我没有时间把它扩展的更全面,这只是个例子</b>
    </BODY>
    </HTML>
      

  19.   

    不死鸟:
    你的方法好像不太适合我的要求哟!
    ---------------------------------to stellaxyq(汐):
    我对你的方案很兴趣,请问htc是菜单组件吗?哪里可以下载?怎么用。
    你的方案可以给个示例代码吗?或者应该看来哪些相关文章?