前面的(
1),(
2),(
3)解决了popup创建Menu的主要技术问题后,现在开始具体的编码心里就有底多了,而且可以把精力集中在逻辑的处理上。当然还有一些UI的问题需要考虑,但都是HTML+CSS的小问题了。
菜单的数据结构其实就是树,由于Menu及MenuItem有很多的自身属性,我们使用面向对象的方式来实现这个菜单。关于JavaScript面向对象的编成不是我讨论的主题,可以参考
蓝色经典上的文章来了解。我们一共实现两个类,一个Menu和一个MenuItem,Menu相当于一个集合,里面容纳n个MenuItem,其上除了菜单的属性外,主要是操作Collection的方法。类的定义如下:
function Menu()
{
this.m_Items = [];
// 菜单条目集合
this.m_Popup =
null;
// 显示菜单的popup窗口
this.m_Invalidate =
false;
// 是否失效标志
this.m_Drawn =
false;
// 菜单是否已输出
this.m_Opener =
null;
// 菜单的父窗口window对象
this.m_ParentMenu =
null;
// 菜单的父菜单MenuItem对象
this.m_ActiveItem =
null;
// 被激活(highlighting)的MenuItem
this.m_ShowTimer =
null;
// 鼠标停留在有子菜单的条目上,子菜单显示延迟计时器
this.m_Bounds =
null;
// 菜单的bounds
this.m_ShowHeaderBlank =
true;
// 是否显示MenuItem前的空白区域
this.m_IsEventAttached =
false;
// 事件是否attached
this.m_Id = __MenuCache__.NewId();
// 或取菜单对象的唯一标识
__MenuCache__[
this.m_Id] =
this;
// 把菜单放入__MenuCache__
this.toString =
function()
{
return '[class Menu]';
};
}
菜单类的方法有:
Menu.prototype.Add =
function(mi)
{
// 添加菜单条目到菜单中
};
Menu.prototype.AddAt =
function(mi, index)
{
// 把菜单条目添加到指定的数组索引上
};
Menu.prototype.AddSeparator =
function()
{
// 添加一个Separator Item,就是我们在window菜单里的"-"
};
Menu.prototype.Remove =
function(mi)
{
// 删除菜单中的一个菜单条目
};
Menu.prototype.Contains =
function(menu)
{
// 判断已构建的菜单中是否已包含了menu
};
Menu.prototype.Render =
function()
{
// 生成菜单UI显示需要的DHTML
};
Menu.prototype.__generatePaddingTR =
function(doc)
{
// 为了美化菜单UI生成的一个TR element
};
Menu.prototype.AttachEvents =
function(menu)
{
// attach事件处理函数到菜单事件上
};
Menu.prototype.ActiveItem =
function(evt)
{
// 处理菜单itme被Active后的UI和动作等
};
Menu.prototype.Hide =
function()
{
// 隐藏菜单
};
Menu.prototype.Keydown =
function(evt)
{
// 处理键盘按键
};
Menu.prototype.Click =
function()
{
// 执行菜单被click
};
Menu.prototype.ResumeItem =
function(evt)
{
// 恢复菜单,取消active和恢复UI
};
Menu.prototype.__resumeItem =
function()
{
// 执行UI恢复
};
Menu.prototype.__resumeAll =
function()
{
// 执行批量UI恢复
};
Menu.prototype.__activeItem =
function()
{
// 执行UI激活
};
Menu.prototype.HasSubMenuExpanded =
function()
{
// 判断菜单是否有展开的submenu
};
Menu.prototype.__isEllipsis =
function(menuObj, menuHtml)
{
// 在菜单item的text过长时将截断并显示""
};
Menu.prototype.Show =
function(evt)
{
// 显示菜单
};
Menu.prototype.InnerShow =
function()
{
// 显示submenu,用于菜单内部触发的菜单显示
};
Menu.prototype.__show =
function(miObj)
{
// 执行菜单显示
};
Menu.prototype.FadeinEffect =
function(effect)
{
// 菜单显示式的特效,是用filter来实现,只在Show菜的时候调用
};
类MenuItem比Menu类简单很多,定义如下:
MenuItem类的方法如下:
MenuItem.prototype.Contains =
function(menu)
{
// 子菜单中是否已添加menu
};
MenuItem.prototype.SetAttribute =
function(key, value)
{
// 设置用户定义的属性
};
MenuItem.prototype.GetAttribute =
function(key)
{
// 或取用户定义的属性
};
MenuItem.prototype.Invalidate =
function()
{
// 失效
};
MenuItem.prototype.IsSeparator =
function()
{
// 判断MenuItem是否为Separator,就是其m_Text == '-'
}
MenuItem.prototype.Render =
function()
{
// 生成菜单UI的DHTML
};
MenuItem.prototype.SetBorderColor =
function(miHtml, width, borderColor)
{
// 设置菜单条目的边框颜色
};
"__"开头的方法是内部方法,不提供给类外使用。变量命名规则m_开头的是类属性变量,Obj结尾的是菜单类对象,和它相对的是Html结尾的,使菜单的HTML元素对象,常见的是menuObj、menuHtml、miObj和miHTML。
Menu类中最重要的方法是:
Menu.prototype.AttachEvents =
function(menu)
Menu.prototype.ActiveItem =
function(evt)
Menu.prototype.HasSubMenuExpanded =
function()
Menu.prototype.Show =
function(evt)
Menu.prototype.InnerShow =
function()
Menu.prototype.__show =
function(miObj)
MenuItem主要是处理UI显示,没有太重要的方法。
本文转自博客园鸟食轩的博客,原文链接:http://www.cnblogs.com/birdshome/,如需转载请自行联系原博主。