77家的会客2010

[ASP]创建一个Yahoo!(TM) 风格的导航条
Weather:穿短袖了,好热呀

创建一个Yahoo!(TM) 风格的导航条
作者:
Jason Withrow

    这个例子将示范如何快速的构造一个简单Yahoo!风格的导航条,它显示了用户到达一个特定的目录的路径,并且显示一个当前目录的子目录的链接的表格。
    开始开发任何数据库驱动的应用程序时,我想做的第一件事情就是设计数据结构。当然,一旦我们开始写代码的时候,列或表与初始设计相比,很多次会被增加或修改,但是有一个数据的框架有助于给我们一些焦点和方向。

数据库规划

    这个例子我使用了一个Access2000 数据库。你一定能容易的把它转变成其它关系型数据库管理系统(RDBMS);只是要遵循同样的表格体系结构。
    让我们先创建一个新的Access数据库, 命名为 Bread.mdb。
    创建一个单独的表,命名为tblParents。以设计模式打开它,并添加下面的列。
Bread.mdb
列的名称        数据类型
AID            自动编号 (主键)
DirName            文本
ChildDir        文本
ParentDir        文本
ChildDirDescript    备注
DirDescript        备注
    * 如果在SQL Server中设计, 要使 AID 列作为一个唯一字段, 增量为1,保证“允许Null”是没有选中。

    下一步,我们需要用数据填充我们的表格,所以让我说明一下体系结构的逻辑。
    从插入你的 web服务器的根目录的数据开始。这是通过在 DirName 列里插入一个前斜线 “/ ”来指定的。
    下一步,在ChildDir 列中添加根下面的目录 (确信你添加了准确的目录名称,因为它会在服务器上出现的)。
    既然这是根目录,保留ParentDir 列为空。对于ChildDirDescript 列,你需要输入任何你希望的链接的文字,它链接到你刚才输入的ChildDir 的目录。(也就是,如果你输入了 music 作为 ChildDir 的名字, 你也许希望指向音乐的链接也读做Music, 所以你在 ChildDirDescript 列输入 Music。如果你希望它读做 Modern Music, 输入它)
    对于 DirDescript 列, 输入你希望描述当前目录的文字,在这个情况下是根文件夹。我用了Home 这个词做为描述,以便用户总是知道点击这个链接将带他回到开始。
    对你的 web 根下的每个子目录重复这个过程。

    注意:如果在你的WEB 服务器上实际的目录结构没有已经存在的话,请确信创建它们。你的数据应该看起来和这个相似:
[upload=gif]/uploadfile/2005-4/access1.gif[/upload]

   完成这个过程后,保证你也在数据库中为你刚才添加的目录加了入口。在我的例子里,我添加了一个目录Music,,所以现在我必须给Music添加适当的字段。既然Music有一个父目录(根),我们必须通过给 ParentDir添加一个前斜线来指定。
    给Music和其它任何你喜欢的子目录添加数据。
    你可以看一下我的例子的屏幕抓图
[upload=gif]/uploadfile/2005-4/access2.gif[/upload]
 * ChildDir 列应该包括根下面的所有目录

代码
    既然我们有了一些有效的数据,让我们先创建几个函数。我们将把这些函数放在一个包含文件里, 命名为 folderFunctions.asp。我们想要的第一个函数是一个返回web服务器上当前物理目录的函数。当查找数据库构造适当的链接和路径历史纪录的时候,我们将会用到它。我把这个函数命名为GetThisPath。
    我们的函数需要做的第一个事情是从服务器上取得当前的完整路径。我们将用ServerVariables 集合的Path_Info方法来查询它。
    因为我们只需要当前目录的名字,我们将以前斜线分离Path_Info返回的字符串,它将创建一个包括当前目录上的所有的目录的数组。我们需要查询整个数据找出我们需要的数据 (当前目录)。我们可以通过设定循环在数据的最后一个元素退出来实现它 (恰好最后一个元素是页面名字,我们不需要它)。我们这样的方法是告诉循环执行数据持续减一的的值对应的次数。我们通过取数组的上界来得到这个信息。
    然后我们将通过在每次循环中覆盖返回值,设置函数返回值为最后一个元素,它就是当前目录。可是,如果这个数据是空的,意味着我们在服务器的根,我们需要设置返回值为一个前斜线,因为那是我们在数据库中为根指定的值。看下面的代码。

Function GetThisPath()
    aPath = Request.ServerVariables("Path_Info")
    pathArr = Split(aPath, "/")
   
    For i = 1 to uBound(pathArr) - 1
        GetThisPath = pathArr(i)
    Next
   
    IF GetThisPath = "" Then
        GetThisPath = "/" 
    End IF
End Function

我们要创建的下一个函数和上一个非常相似,有一点除外,它返回一个当前目录上所有目录的数组, 不仅仅是一个包含当前目录名字的字符串。

Function GetFullPath()
Dim arrFullPath()
    aPath = Request.ServerVariables("Path_Info")
    pathArr = Split(aPath, "/")
   
    IF uBound(pathArr) > 0 Then
        For i = 1 to uBound(pathArr) - 1
            Redim Preserve arrFullPath(i)
            arrFullPath(i) = pathArr(i) & "/"
        Next
    Else
        arrFullPath(0) = "/" 'Root Level
    End IF
   
        GetFullPath = arrFullPath
End Function

现在我们可以开始创建子程序,它会创建实际的到达当前目录的路径列表。完成的输出将看起来象下面的屏幕抓图。
[upload=gif]/uploadfile/2005-4/crumbs1.gif[/upload]
  我把这个子程序命名为BuildCrumbs,因为它将负责创建实际的路径导航条。让我们先创建和打开一个RecordSet,它保存着从我们的数据库中取得的数据。我用的是Jet OLEDB 4 provider。首先我们将定义我们的连接串为strConnect。

strConnect = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath("/data/bread.mdb")
Set oRS = Server.CreateObject("ADODB.Recordset")
strSQL = "SELECT Distinct DirName, ChildDirDescript , DirDescript FROM tblParents"
    oRS.CursorLocation = adUseClient
    oRS.Open strSQL, strConnect, 3, 3

下一步我们将调用开始创建的GetFullPath 函数,并且定义两个空变量,strPath 和strRootPath。

arrPaths = GetFullPath
strPath = ""
strRootPath = ""

 现在我们需要写一些条件选择逻辑。我们需要创建结构,不同地依赖于我们是否在服务器的根级别上。所以我们将调用GetThisPath 函数检查是否我们确实在根上。

If GetThisPath <> "/" Then 

 如果我们不在服务器的根上,那么我们需要构造路径导航条。我们希望我们的路径导航条链接到正确的目录,但是要显示给用户适当的 DirDescript 列的值 。
    我们可以先遍历GetFullPath 函数返回的数组.

For x = 0 To uBound(arrPaths)
    strRootPath = strRootPath & arrPaths(x)
    strPath = Replace(arrPaths(x), "/", "")

   我们需要从数组的值中除去斜线,以便可以和数据库中的名字进行比较。既然我们知道如果我们在循环里,那么当前的用户没有在根级别上,我们需要创建一个返回根的链接。记住这是在一个循环里,我们只希望它执行一次,所以我们将创建一个条件 if 语句。

IF strPath = "" Then
     Response.Write "<a href=" & Q & "/" &  Q & ">Home</a> >> "
End IF

现在我们需要在For循环里嵌套一个RecordSet循环。这是我们和数据库的值比较当前服务器路径并返回适当的值给用户的方法。

oRS.MoveFirst
Do While Not oRS.EOF

   现在我们在两个循环的内部。我们需要比较数组的当前值 (父循环)和当前的数据库纪录 (子循环)。我们可以这样做:有条件的检查每个值并再互相比较。如果他们匹配, 那么我们需要检查来确认当前的 recordset 的值和上次循环执行时不同(因为在我们数据库中,目录有一对多的几率。通过在 recordset 后设置一个变量等于recordset的 DirName列的当前值。我们称这个变量为CurrDirName。下一次循环中,如果CurrDirName 等于 recordset 字段的值,那我们不需要做任何事情。既然我们知道我们将要做什么,那现在就来写这个检查代码吧。

IF Trim(oRS("DirName")) = Trim(strPath) Then
IF CurrDirName <> oRS("DirName") Then

我们需要当心数组的最后一个值(或下标),因为它是当前目录。我们可以这样来检查它,看变量x 是否和数组arrPaths 的上界有相同的值。

IF x < uBound(arrPaths) Then
     Response.Write "<a href=" & Q & "/" & strRootPath & Q & ">" & _
        oRS("DirDescript") & "</a> >> "
Else
    Response.Write "<b>" &  oRS("DirDescript") & "</b>"
End IF

现在关闭我们正在执行的3个条件检查,设置 CurrDirName 的值. 并且让我们的循环继续执行。

End IF
End IF
End IF
currDirName = oRS("DirName")
oRS.MoveNext
    Loop
Next

现在我们只是在最后一个条件If 语句里面,依赖于我们是否在服务器的根。因为如果这个代码正在执行,那么我们确信我们没有在根级别上,但我们仍然需要写一些东西,如果(万一)我们到达了根。所以让我们到前面设立逻辑处理用户在根级别的情况。如果他们在根级别上,我们所要做的就是显示一个无链接文字Home 消息。

Else
     Response.Write "<b>Home</b>"
End IF
oRS.Close
Set oRS = Nothing

这个子程序剩下要做的事情就是关闭recordsets 并释放对象占用的内存。

oRS.Close
Set oRS = Nothing
End Sub

还有一个子程序要写。 这个子程序将创建包含在当前目录中的子目录的列表。它将用来创建html,看起来象下边的屏幕抓图。让我们把这个子程序命名为 PathFill。
[upload=gif]/uploadfile/2005-4/dirLinks.gif[/upload]

 注意:你可以把它写成一个函数,但是既然它没有返回值,我更喜欢把它写成子程序 (你需要的时候可以用古老的void 语句).
    让我们干个不停吧,设立几个ADO存取recordsets的常量。

Const adUseClient = 3
Const adOpenStatic = 3
Const adLockOptimistic = 3

Sub PathFill()

我们需要初始化一个数组,并再一次从数据库字段打开一个recordset,只是这次我们只需要数据库中 DirName 列匹配当前目录的数据。我们将用 GetThisPath 函数帮助我们得到SQL select 语句

Dim arrDirLinks()
strConnect = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _
    Server.MapPath("/data/bread.mdb")

Set oRS = Server.CreateObject("ADODB.Recordset")
    strSQL = "SELECT * FROM tblParents WHERE DirName = '" & _
        GetThisPath & "'"
    oRS.CursorLocation = adUseClient
    oRS.Open strSQL, strConnect, 3, 3

下一步我们需要调用 GetFullPath 函数 并遍历它返回的数组。设置变量strLinkPath 等于它的连接值。我们将用变量strLinkPath 创建当前目录的子目录的链接。

arrSQLPaths = GetFullPath
    If GetThisPath  "/" Then 
        For y = 0 To uBound(arrSQLPaths)
            strLinkPath = strLinkPath & arrSQLPaths(y)
        Next
    End IF

 现在我们想遍历我们的recordset,并给我们的包含实际html链接的arrDirLinks 数组添加一个下标,这是通过从recordset中分解得到的。只要有一个子目录要列出并且我们不在服务器的根,我们就需要这样做。 我们的数组需要和 recordset有相同数量的下标, 所以我们用一个变量 (我称为 x) 跟踪这个数字。

oRS.MoveFirst
x = 0
Do While Not oRS.EOF
ReDim Preserve arrDirLinks(x)
IF oRS("ChildDir")  "" OR oRS("DirName") = "/" Then
    arrDirLinks(x) = "
        & strLinkPath & oRS("ChildDir") & Q & ">" _
        & oRS("ChildDirDescript") & ""
End IF
oRS.MoveNext
x = x + 1
Loop

 最后,我们需要关闭recordsets,释放内存并给 arrDirLinks 数组 session 作用域。子程序完成了。

oRS.Close
Set oRS = Nothing

Session("arrDirLinks") = arrDirLinks
End Sub

现在添加初始的html到这个包含文件(folderFunctions.asp)的底部并把它保存在 includes文件夹中。

<html><head>
    <title>BreadCrumbs</title>
    <link rel="STYLESHEET" type="text/css" href="/includes/crumbs.css">
</head>

让我们给所在的这个目录添加另一个包含文件。我们称它为topCrumbs.asp,它将显示路径导航条给用户。

<table border="0" style="background: silver" width="100%">
    <tr>
        <td valign="top"><% Call buildCrumbs %></td>
    </tr>
</table>

    剩下要做的就是设立最后一个包含文件,它显示当前目录的子目录的列表。把它命名为buildChildLinks.asp。
    基本上,我们希望它做的就是遍历arrDirLinks 数组并创建链接的列表。我还希望链接创建在一个两列的表格里,所以我写了一些逻辑检查是否数组保存了偶数的下标,并适当的格式化链接的表格。我们将设置一个名为blnEven的布尔变量,它是True 还是 False取决于返回一个偶数还是奇数。我们还希望给我们的链接设置HTML。看下面。

<ul style="list-style-type: square">
<table Border="0" CellSpacing="3" CellPadding="3">
<tr><% CR = Chr(10) & Chr(13)
     PathFill()
    arrDirLinks = Session("arrDirLinks")
     IF (uBound(arrDirLinks) Mod 2) = 0 Then
        blnEven = True
     Else
        blnEven = False
     End IF

现在我们只是用一个Select Case 语句基于返回一个偶数还是奇数来创建HTML。

Select Case blnEven
Case False
For i = 0 To uBound(arrDirLinks)

    IF (i MOD 2) = 0 Then
        Response.Write " "
    Else
        Response.Write " "
    End IF

    Response.Write arrDirLinks(i)

    IF (i MOD 2) = 0 Then
        Response.Write "" & CR
    Else
        Response.Write " " & CR
    End IF
Next

Case True
For i = 0 To uBound(arrDirLinks)
On Error Resume Next
IF i
    IF (i MOD 2) = 0 Then
        Response.Write "&nbsp; "
    Else
        Response.Write "&nbsp; "
    End IF

    Response.Write arrDirLinks(i)

    IF (i MOD 2) = 0 Then
        Response.Write "" & CR
    Else
        Response.Write " " & CR
    End IF
Else
    IF arrDirLinks(i)  "" Then
        Response.Write "&nbsp;" _
            & "" _
            & arrDirLinks(i) & ""
    End IF
End IF
Next
   
End Select
%>
</table></ul>

就是它了! 现在我们所有要做的就是把所有的包含文件一起放在一个单独的页面里并且在所有目录的页面中放置这个页面。

<!--#include virtual="/includes/folderFunctions.asp"-->
<body>
<!-- Top 路径导航条 -->
<!--#include virtual="/includes/topCrumbs.asp"-->
<!-- End Crumbs -->
<table border="0">
<tr>
    <td valign=top>
    <p>    Just some meaningless text here.<br>
    You would probably want to put your own stuff in here.<br>
    And not just ramble on like I am doing.
        <p>Well, See you all later.   
</td><tr>
    <td valign="top">
    <!-- Nested Table to simulate Real Page Data -->
    <!-- Build Links to Sub Directories -->
    <!--#include virtual="/includes/buildChildLinks.asp"-->
<!-- End Build Links -->
    </td>
</tr></table>
</body></html>

  注意: 你可以用整个的应用程序,如果你愿意的话,你也可以打散它,通过在你的页面中只包含相关的包含文件,就可以只利用顶部的路径导航条功能或创建子链接功能。
    支持信息
你可以从这里下载一个包含这篇文章的源代码和示范数据库的zip格式的压缩文件。我希望你能发现这篇文章的价值,并且它能提供一些意味深长的感悟。 你可以联系我在
[email protected]
(5天后)或在
[email protected]
(今天)。

原文地址:
[url]http://www.blueidea.com/bbs/NewsDetail.asp?GroupName=Dreamweaver+MX+Developer+%D3%EB%CA%FD%BE%DD%BF%E2%B1%E0%B3%CC&DaysPrune=60&lp=1&id=2010349[/url]
===============================================

个人评论:

这个分类法,在我看来,是属于有限分类和无限级分类之间的一种很好的思路了,首先,她的设计思路不像无限级分类那么烦覆,对于一个非报表类型的网站来说,是很好用的了,有哪个非报表类的网站能有Yahoo目录更复杂?不管有没有,至少对于非超重量级的客户来说,都足够用了.这个分类方法,相对于我原来自己设计那个就是考虑到SQL注入了,目录都是使用的字符串,而我原来的级别之间的关系都是采用的数字做为链接的,这样就得凭空多出好多处理,并且也不直观.

历史上的今天: [2010/04/29]外甥女

[ [ASP]创建一个Yahoo!(TM) 风格的导航条]的回复

Post a Comment~