在公司内部网站中,一个直观且易于导航的菜单是至关重要的。最近一直在思考如何为公司内部网站创建一个这样的菜单。感到有些内疚,因为一直在使用这里提供的许多优秀代码。因此,决定分享几年前创建的一个数据库生成的菜单,希望这对中的一些人来说可能是有用的。
虽然相信菜单生成器可能已经被其他人实现过,但仍然认为它有一些独特的优点。其中一个原因是它可以在保持固定的两行格式的同时,向前和向后遍历。在开始之前,要提醒大家,代码可能很粗糙且过时,但谁在乎呢,让假装它是伪代码。
以下是菜单在遍历时的样子的一些示例(附带的图片并没有真正展示这一点)。这是默认设置:
点击“首页”将带来到这里:
点击“外部”将得到以下结果:
最后,点击“Microgaming”将显示这个:
如果按照所做的步骤操作,可以看到菜单是如何遍历的,并且上一个选择总是显示出来,以便在出错时可以向后导航。
菜单项存储在一个简单的数据库表中,包含所需的信息。以下是创建表格的方式:
USE [Utopia]
GO
CREATE TABLE [dbo].[MENU](
[LEVELID] [int] IDENTITY(1,1) NOT NULL,
[LEVELCODE] [int] NOT NULL,
[DESCRIPTION] [varchar](25) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[LEVELWITHIN] [int] NOT NULL,
[URL] [varchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[HINT] [varchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[IMAGEURL] [varchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[CREATIONDATE] [datetime] NOT NULL,
[USERTXN] [varchar](25) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
CONSTRAINT [PK_MENU] PRIMARY KEY CLUSTERED
(
[LEVELID] ASC
)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
这里最重要的项是级别ID和级别内,它们定义了导航顺序。这类似于树中的子节点和父节点。
也可以从XML文件或Web服务读取项目。一切都取决于。菜单的呈现是通过一个自定义控件(ascx文件)和一个简单的文本Web控件完成的:
litMenu.Text = GenerateMenu(myMenu);
其中myMenu对象很简单:
using System;
namespace SmartNav
{
public class MenuHelper
{
protected int _Level;
protected int _Parent;
protected Boolean _Row1;
protected Boolean _Row2;
public int Level
{
get { return _Level; }
set { _Level = value; }
}
public int Parent
{
get { return _Parent; }
set { _Parent = value; }
}
public Boolean Row1
{
get { return _Row1; }
set { _Row1 = value; }
}
public Boolean Row2
{
get { return _Row2; }
set { _Row2 = value; }
}
}
}
在调用GenerateMenu(MenuHelper inMenu)过程之前,有一些代码(相当丑陋但功能齐全,请参阅源代码),它使用cookie保存菜单导航,并在没有cookie的情况下加载默认位置。
以下是代码的核心部分,实际上是创建菜单的地方:
private string GenerateMenu(MenuHelper inMenu)
{
string menuStr;
MenuRow headerRow = new MenuRow();
MenuRow navigationItem = new MenuRow();
SmartNav menu = new SmartNav();
SqlDataReader dr;
MenuRow menuRow;
ArrayList menuItems = new ArrayList();
menu.WriteStartMenu();
menu.WriteNewLine();
#region Fetch First Row from DB
...
#endregion Fetch First Row
menu.WriteHeaderItem(headerRow);
menu.WriteMenuItem(menuItems);
navigationItem.Top = (int)SqlHelper.ExecuteScalar(
System.Configuration.ConfigurationSettings.AppSettings["ConnectionStringUTOPIA"],
CommandType.StoredProcedure,
"ReturnParent",
new SqlParameter("@inLoc", navigationItem.Top));
menu.WriteNavigationItem(navigationItem, 0, Request["s"]);
menu.WriteEndLine();
menuItems.Clear();
menu.WriteNewLine();
if (inMenu.Parent != 0)
{
#region Fetch Second Row from DB
...
#endregion Fetch Second Row
menu.WriteHeaderItem(headerRow);
menu.WriteMenuItem(menuItems);
navigationItem.ID = (int)SqlHelper.ExecuteScalar(
System.Configuration.ConfigurationSettings.AppSettings["ConnectionStringUTOPIA"],
CommandType.StoredProcedure,
"ReturnTop"
);
menu.WriteNavigationItem(navigationItem, 1, Request["s"]);
}
else
{
menu.WriteHeaderItem();
menu.WriteMenuItem();
menu.WriteNavigationItem();
}
menu.WriteEndLine();
menu.WriteEndMenu();
menuStr = menu.WriteMenu();
menuItems.Clear();
menu.Close();
return menuStr;
}
基本上就是这样。代码需要进行大量的重构,但总的来说,都可以假装它是伪代码,并且它是有效的。
有很多修改可以对菜单生成器进行(除了代码重构/重写):