ASP.NET 菜单父菜单项高亮显示






4.78/5 (14投票s)
ASP.NET 菜单父菜单项高亮显示的解决方法。
引言
这是 ASP.NET 2.0 菜单控件父菜单项高亮显示的简单解决方法。
背景
我有一些网站,它们的菜单结构相对庞大且层级很深。如果用户在 ASP.NET 菜单中用鼠标滚动了很多层,菜单的外观会变得有点过于复杂,用户可能会对当前菜单项的父项感到困惑。
有一个叫做 CSS Friendly Adapters 的解决方案。我尝试过使用它,但我认为它充满了 bug,而且行为经常非常疯狂且令人烦恼。原始的 ASP.NET 菜单控件和使用 CSS Friendly Adapters 的 ASP.NET 菜单之间存在**大量**差异,我并不喜欢这样...
Using the Code
首先,这不是最美的解决方案,但它有效。起初,我希望在服务器端完成所有事情,但我发现 MenuItem
不继承自 Control
,因此它没有可以操作的客户端属性。因此,我决定查看 ASP.NET 菜单生成的客户端代码。我注意到它是一个大表格,其中一些行具有 ID
属性,这些属性以 ASP.NET 菜单的 ClientID
开头,并带有 OnMouseOver
和 OnMouseOut
事件处理程序。我稍微玩弄了一下事件处理程序,并发现如果我从 JavaScript 中显式调用它们,就可以高亮显示任何菜单项。
因此,我只需要弄清楚 ASP.NET 菜单如何生成客户端 ID。这非常简单。如果在服务器端递归搜索菜单项,你只需要用一个简单的计数器为它们编号,你就可以得到生成的菜单项的客户端编号。下面是搜索菜单项的代码:
void FindMenuItems(MenuItem mi, List<MenuItem> list)
{
foreach (MenuItem child in mi.ChildItems)
{
list.Add(child);
}
foreach (MenuItem child in mi.ChildItems)
{
FindMenuItems(child, list);
}
}
我们有了菜单项,现在我们需要遍历列表,并找到每个菜单项的所有父项(直到根)。
下面是搜索菜单项父项的代码:
void FindParents(MenuItem mi, List<MenuItem> list)
{
if(mi.Parent != null)
{
if(mi.Parent != mainMenu.Items[0])
{
list.Add(mi.Parent);
FindParents(mi.Parent, list);
}
}
}
整合
在 Page_Load
事件处理程序中,我对每个菜单项调用上述方法。我找到每个父项(直到根),并计算当前菜单项和父菜单项的客户端 ID。我将父菜单项的客户端 ID 连接成一个逗号分隔的字符串。最后,我为每个菜单项绑定一个客户端 OnMouseOver
和 OnMouseOut
事件处理程序。我将两个参数传递给这些事件处理程序:菜单项的客户端 ID,以及包含菜单项父项的逗号分隔字符串。
List<MenuItem> list = new List<MenuItem>();
list.Add(mainMenu.Items[0]);
FindMenuItems(mainMenu.Items[0], list);
foreach (MenuItem mi in list)
{
List<MenuItem> parents = new List<MenuItem>();
FindParents(mi, parents);
string parentSnake = String.Empty;
foreach (MenuItem parent in parents)
{
parentSnake += "mainMenun" + list.IndexOf(parent).ToString() + ",";
}
parentSnake.TrimEnd(',');
script += "document.getElementById(
'" + mainMenu.ClientID + "n" +
list.IndexOf(mi).ToString() + "').onmouseover =
function(){HoverParents('" + mainMenu.ClientID +
"n" + list.IndexOf(mi).ToString() + "', '" + parentSnake + "')};";
script += "document.getElementById('" + mainMenu.ClientID + "n" +
list.IndexOf(mi).ToString() +
"').onmouseout = function(){UnhoverParents('" +
mainMenu.ClientID + "n" + list.IndexOf(mi).ToString() + "', '" +
parentSnake + "')};";
}
ScriptManager.RegisterStartupScript(this, typeof(string),
"MenuHoverUnhover", script, true);
事件处理程序是用 JavaScript 编写的。OnMouseOver
会高亮显示实际的菜单项,就像原始的 ASP.NET 生成代码那样(使用相同的调用方法),然后遍历父项的逗号分隔列表,并以相同的方式高亮显示它们。OnMouseOut
则做相反的事情。
function HoverParents(id, parentSnake)
{
Menu_HoverDynamic(document.getElementById(id));
var parents = parentSnake.toString().split(',');
for(i = 0;i < parents.length;i++)
{
if(parents[i] != '')
{
Menu_HoverDynamic(document.getElementById(parents[i]));
}
}
}
function UnhoverParents(id, parentSnake)
{
Menu_Unhover(document.getElementById(id));
var parents = parentSnake.toString().split(',');
for(i = 0;i < parents.length;i++)
{
if(parents[i] != '')
{
Menu_Unhover(document.getElementById(parents[i]));
}
}
}
一旦我们得到绑定事件处理程序的客户端脚本,我就会使用 Script Manager 在每次 postback 时将 JavaScript 嵌入到页面中。
关注点
依赖客户端生成的 ID 不是你能选择的最佳方法,但有时,它很简单,并且效果很好。