1. 论坛系统升级为Xenforo,欢迎大家测试!
    排除公告

无限分类的 ASP 实现方式

本帖由 不学无术2005-10-16 发布。版面名称:后端开发

  1. 不学无术

    不学无术 Ulysses 的元神

    注册:
    2005-08-31
    帖子:
    16,714
    赞:
    39
    做网站的,应该经常遇到使用分类功能的,通常有个二级三级分类已经很不错,在实现上,这些也不是很难的。但是对于某些系统,却需要实现更多级分类,例如文章系统,分类级数是不确定的,所以现在网上的系统中基本都采用无限分类。

    看到很多地方都有关于无限分类实现的教程,也有人说这个是非常简单的功能。简单与否,在于每个人的能力了。

    现在我们也来考察一下如何实现这个无限分类。在这里我采用的是 ASP(VBScript) 结合 Access 数据库来实现。

    通常对于分类,我们需要有类别的编号和类别的名称,所以我们在数据库中定义这两个字段,ID 和 Title,ID 字段为自动编号,Title 选择文本类型。

    但是如果仅有这两个字段,能实现的恐怕只有一级分类了。多级分类中,不同级之间都会存在关联性,即每个子类别,都应该是唯一地属于某个父类别的,所以在数据库中,我们表现出当前子类别所属的父类别即可。鉴于此,我们增加一个字段ParentID,保存父类别 ID 值。对于根类别,我们可以设置这个值为 0 。

    至此,基本上就可以具备了无限级分类所必需的数据。

    但是在实际使用中,出于效率问题,我们增加进两个字段:

    IDPath - 用来保存当前类别的 ID 路径,即从顶层到当前类别的各级分类的 ID ,各级层间用分隔符“|”分隔。
    TitlePath - 用来保存当前类别的 Title 路径,即每级分类的标题,各级层间用分隔符“|”分隔。

    鉴于是要实现无限分类,上面两个字段的内容可能会很长,所以我们选择备注类型。具体的作用,在后面的程序中可以明了。

    这样我们得到完整的数据库:

    ID - 分类编号 - 自动编号
    Title - 分类标题 - 文本
    ParentID - 父类别编号 - 整数
    IDPath - 分类层次编号路径 - 备注
    TitlePath - 分类层次标题路径 - 备注

    - 未完待续 -
     
    #1 不学无术, 2005-10-16
    最后编辑: 2005-10-16
  2. 不学无术

    不学无术 Ulysses 的元神

    注册:
    2005-08-31
    帖子:
    16,714
    赞:
    39
    我们首先来考察如何显示表中已经存在的数据。先给出代码:

    代码:
    Sub listData
        Dim intSortID : intSortID = CID(Request.QueryString("SortID"))
    	
    	Dim rs, sql
    	Set rs = Server.CreateObject("ADODB.Recordset")
    	sql = "SELECT s.ID, s.Title, s.IDPath, s.TitlePath, (SELECT Count(*) FROM Sorts ss WHERE ss.ParentID = s.ID) AS iCount FROM Sorts s WHERE s.ParentID = " & intSortID & ";"
    	rs.Open sql, conn, 1, 1, 1
    	If rs.RecordCount > 0 Then
    	    Dim arrIDs, arrTitles, intLoop
    		
    	    Response.Write("<table width=""100%"" cellpadding=""3"" cellspacing=""1"" border=""0"" bgcolor=""#CCCCCC"">")
    		Response.Write("<tr bgcolor=""#E0E0E0""><th>分类名</th><th>子类别数目</th><th>分类层级</th></tr>")
    		
    		Do While Not rs.EOF
    		    Response.Write("<tr bgcolor=""#FFFFFF""><td><a href=""?action=list&SortID=" & rs("ID") & """>" & rs("Title") & "</a>&nbsp;<img src=""images/icon_new_window.gif"" width=""11"" height=""14"" border=""0"" alt=""打开功能菜单"" title=""打开功能菜单"" onclick=""showMenu(event, '', '" & rs("ID") & "');"" /></td><td>" & rs("iCount") & "</td><td><a href=""?action=list&SortID=0"">根</a>&nbsp;&raquo;&nbsp;")
    			
    			'    数据入库的时候保证 IDPath 和 TitlePath 不为空
    			arrIDs = Split(rs("IDPath"), "|")
    			arrTitles = Split(rs("TitlePath"), "|")
    			
    			For intLoop = 0 To UBound(arrIDs)
    			    If intLoop = UBound(arrIDs) Then    '    如果是最后一级
    				    Response.Write("<a href=""?action=list&SortID=" & arrIDs(intLoop) & """>" & arrTitles(intLoop) & "</a>")
    				Else
    				    Response.Write("<a href=""?action=list&SortID=" & arrIDs(intLoop) & """>" & arrTitles(intLoop) & "</a>&nbsp;&raquo;&nbsp;")
    				End If
    			Next
    			
    			Response.Write("</td></tr>")
    			
    			rs.MoveNext
    		Loop
    		
    		Response.Write("</table>")
    	Else
    	    Response.Write("暂无子类别,是否<a href=""?action=add&SortID=" & intSortID & """>添加</a>?")
    	End If
    	rs.Close
    	Set rs = Nothing
    End Sub
    我们将列出分类的代码写入一段子程序 listData,其中变量 intSortID 是传递过来的一个类别编号,而我们要显示的是该类别下的子类别。

    对于第一级分类,这个编号为 0。

    CID() 函数是自定义的函数,用于将字符串转换为 ID 类型的数据,即大于等于 0 的整数,后面还会多次用到这个自定义函数,代码如下:

    代码:
    '--------------------------------------------------------------------------------
    Function CID(strS)
    '--------------------------------------------------------------------------------
    '    转换为有效的 ID
    '    返回值类型:Integer (>=0)
    '--------------------------------------------------------------------------------
        Dim intI
    	intI = 0
    	
        If IsNull(strS) Or strS = "" Then
    	    intI = 0
    	Else
    	    If Not IsNumeric(strS) Then
    		    intI = 0
    		Else
    		    Dim intk
    		    On Error Resume Next
    			intk = Abs(Clng(strS))
    			If Err.Number = 6 Then intk = 0  ''数据溢出
    			Err.Clear
    		    intI = intk
    		End If
    	End If
    	
    	CID = intI
    End Function
    数据库操作,就是从表中找到 ParentID = intSortID 的记录,然后循环显示。

    在针对 IDPath 和 TitlePath 这两个字段的内容上,定义两个数组 arrIDs 和 arrTitles ,分别循环显示类别层次即可。这里需要注意最后一个层次(在我的代码中,最后一级即为当前分类),其后是不包括箭头标示的,表示已经是当前分类了。

    当没有记录的时候,显示提示信息,并有一个增加分类的链接。

    因为所有的添加、编辑、删除、列表操作我放在一个页面中,所以链接中有个 action 变量来确定是进行哪步操作。

    另外,显示的分类标题后面有个小图标,点击能显示功能菜单,相应的代码在后面给出。

    - 未完待续 -
     
    #2 不学无术, 2005-10-17
    最后编辑: 2005-10-18
  3. wm_chief

    wm_chief New Member

    注册:
    2005-09-05
    帖子:
    17,890
    赞:
    46
    不错噢