正大互联的结构思想:

序号 字段名 类型 大小 说明
1 ID int 4 主键,自增。
2 parentID int 4 父节点。
3 path nvarchar 100 父节点的集合。
4 noteLevel int 4 层数,从1开始计算。
5 isShow nvarchar 50 第一次填充树的时候,是否显示该节点。true/false
6 OrderID int 4 排序字段。
3 noteTitle nvarchar 100 节点名称。
3 WebUrl nvarchar 100 点击节点时打开的网页。如果是#则不打开网页
3 Target nvarchar 100 打开网页的目标。

这个是在无限分级的表的基础上,改进了一下。有几个字段要特殊说明一下

1、path:拿我的电脑来比喻,比如一个文件a.mp3放在了“c:/myDoc/miusic/”里面,如果 a.mp3 是一个节点的话,那么“c:/myDoc/miusic/”就是 path 。

一级节点的parentID都是0,path 也都是0;其他节点的path 就是 父结点的path + "," + 父节点ID。

设置这个字段的目的是可以一次(避免了递归)找到一个节点的子节点、子子节点……,在收拢节点的时候特别有用。

2、OrderID:为什么只用一次绑定就可以了呢?关键就在这里。一个DIV就是一个节点,那么DIV的先后顺序是由谁来决定的呢?不是parentID,也不是path。而是OrderID。

在显示数的时候,谁排在上面,谁排在下面,完全是由OrderID来决定的,这样只需一次绑定就ok了。

当然,在添加、移动、删除节点上带来了不小的麻烦。但是考虑到维护的次数是很少的,对于树的显示次数来说名可以忽略不计了,所以我觉得这么做是值得的。

3、noteLevel:这个决定了节点的外观,把它加到CSS得名称上面,就可以区分不同级别的节点了。在展开节点的时候也会用到。

其他的就没有什么了。

展开和收拢的效果就交给javascript了


   function showme(me){
  
       var myID = me.id.replace("n","");
       var Level = notes[myID][0];
       var path = notes[myID][1];
       var url = notes[myID][2];
       var target = notes[myID][3];
       var isshow = notes[myID][4];
      
       //判断是否打开网页
       if (url != "#"){
           if (target =="main")
               parent.document.getElementById("frmMain").src= url + "?id=" + myID;
           else
               window.open(url,target)
       }   
          
       var tmpNote;
       pID = "," +myID+ ",";
       for(var i=1;i< notes.length;i++)
       {
           tmpID = "," + notes[1] + ",";
           if (myID != notes[1])
               if (tmpID.indexOf(pID) !="-1" )
                   showDIV(myID,i);
          
       }
       if (isshow =="True")
           notes[myID][4] ="False";        //notShow
       else
           notes[myID][4] ="True";            //show
          
   }
   function showDIV(parentID,sonID){
       var myDIV = document.getElementById("n" + sonID);
       var parent = document.getElementById("n" + parentID);
      
       if (notes[parentID][4] == "True" ){
           myDIV.style.display = "none";        //notShow
           notes[sonID][4] = "False"
       }
       else{
           if (notes[sonID][0] - notes[parentID][0] =="1")
               myDIV.style.display="";   
       }
      
   }
   </script>

可以用repeater作为树的容器

我整理后的完整代码

.cs

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Configuration;
using System.Data.SqlClient;
namespace tree
{
    
/// <summary>
    
/// WebForm1 的摘要说明。
    
/// </summary>

    public class WebForm1 : System.Web.UI.Page
    
{
        
protected System.Web.UI.WebControls.Repeater Repeater1;
        DataSet ds 
= new DataSet();
        SqlConnection con 
= new SqlConnection();
        
private void Page_Load(object sender, System.EventArgs e)
        
{
            
// 在此处放置用户代码以初始化页面
            con = new SqlConnection(ConfigurationSettings.AppSettings["Sqlcon"]);
            
string sql = "select * from office where isdelete=0";
            SqlDataAdapter da 
= new SqlDataAdapter(sql,con);
            da.Fill(ds);
            
this.Repeater1.DataSource = ds.Tables[0].DefaultView;
            
this.Repeater1.DataBind();
            
////
            Response.Write("<script language=\"javascript\">var notes = new Array();");
            Response.Write(
"var a = notes;\r\n");
            
foreach(DataRow dr in ds.Tables[0].Rows)
            
{
                Response.Write(
"a[");
                Response.Write(dr[
"id"].ToString());           
                Response.Write(
"] = new Array('");
                Response.Write(dr[
"noteLevel"].ToString());               
                Response.Write(
"','");
                Response.Write(dr[
"path"].ToString());                 
                Response.Write(
"','");
                Response.Write(dr[
"weburl"].ToString());              
                Response.Write(
"','");
                Response.Write(dr[
"target"].ToString());              
                Response.Write(
"','");
                Response.Write(dr[
"isshow"].ToString());             
                Response.Write(
"')\r\n");
            }

            Response.Write(
"</script>");
        }


        
Web 窗体设计器生成的代码
    }

}

.aspx

<HTML>
    
<HEAD>
        
<title>WebForm1</title>
        
        
<meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
        
<meta name="CODE_LANGUAGE" Content="C#">
        
<meta name="vs_defaultClientScript" content="JavaScript">
        
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
        
<script language="javascript">
    function showme(me)
{
    
        var myID 
= me.id.replace("n","");
        var Level 
= notes[myID][0];
        var path 
= notes[myID][1];
        var url 
= notes[myID][2];
        var target 
= notes[myID][3];
        var isshow 
= notes[myID][4];
        
        
//判断是否打开网页
        if (url != "#"){
            
if (target =="main")
                parent.document.getElementById(
"frmMain").src= url + "?id=" + myID;
            
else
                window.open(url,target)
        }
    
            
        var tmpNote;
        pID 
= "," +myID+ ",";
        
for(var i=1;i< notes.length;i++)
        
{
            tmpID 
= "," + notes[i][1+ ",";
            
//找自己的所有子节点
            if (tmpID.indexOf(pID) !="-1" )
                
//window.setTimeout("showDIV("+myID+","+i+")",200);
                showDIV(myID,i);
            
        }

        
//for(var i=1;i< notes.length;i++)
        
//{
                    
            
//找父结点的子节点        
            
//if (notes[myID][1] == notes[i][1] && myID != i)
                
//noneOtherDiv(i);
            
        
//}
        if (isshow =="True")
            notes[myID][
4="False";        //notShow
        else
            notes[myID][
4="True";            //show
            
    }

    function noneOtherDiv(parentID)
    
{    
        
for(var i=1;i< notes.length;i++)
        
{
            
//找子节点        
            if (notes[parentID][1+ "," + parentID == notes[i][1] )
            
{
                var tmp 
= document.getElementById("n" + i);
                tmp.style.display 
= "none";
                notes[i][
4= "False"
            }

            
        }

    }

    
    function showDIV(parentID,sonID)
{
        var myDIV 
= document.getElementById("n" + sonID);
        var parent 
= document.getElementById("n" + parentID);
        
        
if (notes[parentID][4== "True" ){
            myDIV.style.display 
= "none";        //notShow
            notes[sonID][4= "False"
        }

        
else{
            
if (notes[sonID][0- notes[parentID][0=="1")
                myDIV.style.display
="";    
        }

        
    }

        
</script>
</HEAD>
    
<body MS_POSITIONING="GridLayout">
        
<form id="Form1" method="post" runat="server">
            
<TABLE id="Table1" style="Z-INDEX: 101; LEFT: 144px; WIDTH: 112px; POSITION: absolute; TOP: 72px; HEIGHT: 304px"
                cellSpacing
="1" cellPadding="1" width="112" border="1">
                
<TR>
                    
<TD colSpan="3" valign=top><FONT face="宋体">
                            
<asp:Repeater id="Repeater1" runat="server" EnableViewState="False">
                                
<ItemTemplate>
                                    
<div id='n<%#DataBinder.Eval(Container,"DataItem.id")%>' onclick="showme(this)"><%#DataBinder.Eval(Container,"DataItem.name")%></div>
                                
</ItemTemplate>
                            
</asp:Repeater></FONT></TD>
                
</TR>
            
</TABLE>
        
</form>
    
</body>
</HTML>
数据库中的id是自增长的,但要是id的值不是连续的话就会出现问题。