在使用...(5)中用Show()把菜单显示出来了,Show中的大部分大代码都很好理解,这节主要说一下event的处理,在Show的末尾我们使用了一个AttachEvents()方法来attach鼠标和键盘的事件,该方法的代码如下:
使用Popup窗口创建无限级Web页菜单(6)Menu.prototype.AttachEvents = function(menuHtml)
使用Popup窗口创建无限级Web页菜单(6){
使用Popup窗口创建无限级Web页菜单(6)    
var menuObj = __MenuCache__[menuHtml.uniqueId];
使用Popup窗口创建无限级Web页菜单(6)    
if ( menuObj.m_IsEventAttached )
使用Popup窗口创建无限级Web页菜单(6)    {
使用Popup窗口创建无限级Web页菜单(6)        
return;
使用Popup窗口创建无限级Web页菜单(6)    }
使用Popup窗口创建无限级Web页菜单(6)    
var doc = menuObj.m_Popup.document;
使用Popup窗口创建无限级Web页菜单(6)    
for ( var i=0 ; i < menuObj.m_Items.length ; ++i )
使用Popup窗口创建无限级Web页菜单(6)    {
使用Popup窗口创建无限级Web页菜单(6)        
var mItem = menuObj.m_Items[i];
使用Popup窗口创建无限级Web页菜单(6)        
var trItem = doc.getElementById(mItem.m_Id);
使用Popup窗口创建无限级Web页菜单(6)        
if ( mItem.m_Action && !mItem.m_ChildMenu )
使用Popup窗口创建无限级Web页菜单(6)        {
使用Popup窗口创建无限级Web页菜单(6)            
if ( !mItem.IsSeparator() )
使用Popup窗口创建无限级Web页菜单(6)            {
使用Popup窗口创建无限级Web页菜单(6)                trItem.attachEvent('onclick', mItem.m_Action);
使用Popup窗口创建无限级Web页菜单(6)                trItem.attachEvent('onclick', Menu.HideAllPopups);
使用Popup窗口创建无限级Web页菜单(6)            }
使用Popup窗口创建无限级Web页菜单(6)        }
使用Popup窗口创建无限级Web页菜单(6)        
if ( mItem.m_ChildMenu )
使用Popup窗口创建无限级Web页菜单(6)        {
使用Popup窗口创建无限级Web页菜单(6)            trItem.attachEvent('onmousedown', 
this.InnerShow);
使用Popup窗口创建无限级Web页菜单(6)        }
使用Popup窗口创建无限级Web页菜单(6)        
if ( !mItem.IsSeparator() )
使用Popup窗口创建无限级Web页菜单(6)        {
使用Popup窗口创建无限级Web页菜单(6)            trItem.attachEvent('onmouseover', 
this.ActiveItem);
使用Popup窗口创建无限级Web页菜单(6)        }
使用Popup窗口创建无限级Web页菜单(6)    }
使用Popup窗口创建无限级Web页菜单(6)    menuHtml.attachEvent('onmouseout', 
this.ResumeItem);
使用Popup窗口创建无限级Web页菜单(6)    
if ( doc )
使用Popup窗口创建无限级Web页菜单(6)    {
使用Popup窗口创建无限级Web页菜单(6)        doc.attachEvent('onkeydown', 
this.Keydown);
使用Popup窗口创建无限级Web页菜单(6)    }
使用Popup窗口创建无限级Web页菜单(6)    menuObj.m_IsEventAttached 
= true;
使用Popup窗口创建无限级Web页菜单(6)};
    方法中的第一句:var menuObj = __MenuCache__[menuHtml.uniqueId];,就是我在使用...(3)中说过的为什么要用__MenuCache__。因为menuObj是JavaScirpt类实例,而menuHtml是DHTML的UI元素,他们在使用innerHTML赋值传递时失去了彼此的引用联系,而__MenuCache__里mapping了它们的一对一关系。Menu类中还有很多方法中都用到了类似__MenuCache__[id]这样的调用,而所有用到这种方法的地方,都是为了把object和html映射起来。

    由于attachEvent方法的操作类似一个压栈的过程,执行它是不会检查同一个事件是否已被attach了的,所以需要自己记录菜单是否已attach事件的标志,在执行attach操作前判断。第二个要注意的是,在向事件上attach处理方法时,由于方法都是Menu类内部的方法,都是使用this.MethodName来引用的,而在这些方法的实现中,是不能使用this这个关键字来指代Menu类的当前实例的,我下面用this.ResumeItem的调用来说明,ResumeItem()的源代码如下:
使用Popup窗口创建无限级Web页菜单(6)Menu.prototype.ResumeItem = function(evt)
使用Popup窗口创建无限级Web页菜单(6){
使用Popup窗口创建无限级Web页菜单(6)    
if ( !evt || evt.toElement )
使用Popup窗口创建无限级Web页菜单(6)    {
使用Popup窗口创建无限级Web页菜单(6)        
return;
使用Popup窗口创建无限级Web页菜单(6)    }
使用Popup窗口创建无限级Web页菜单(6)    
var menuHtml = FindParentElement(evt.srcElement, 'TABLE');
使用Popup窗口创建无限级Web页菜单(6)    
if ( !menuHtml.uniqueId ) 
使用Popup窗口创建无限级Web页菜单(6)    {
使用Popup窗口创建无限级Web页菜单(6)        menuHtml 
= FindParentElement(menuHtml.parentElement, 'TABLE');
使用Popup窗口创建无限级Web页菜单(6)    }
使用Popup窗口创建无限级Web页菜单(6)    
var menuObj = __MenuCache__[menuHtml.uniqueId];
使用Popup窗口创建无限级Web页菜单(6)    
if ( menuObj.HasSubMenuExpanded() )
使用Popup窗口创建无限级Web页菜单(6)    {
使用Popup窗口创建无限级Web页菜单(6)        
return;
使用Popup窗口创建无限级Web页菜单(6)    }
使用Popup窗口创建无限级Web页菜单(6)    
if ( menuObj.m_ShowTimer )
使用Popup窗口创建无限级Web页菜单(6)    {
使用Popup窗口创建无限级Web页菜单(6)        window.clearTimeout(menuObj.m_ShowTimer);
使用Popup窗口创建无限级Web页菜单(6)        menuObj.m_ShowTimer 
= null;
使用Popup窗口创建无限级Web页菜单(6)    }
使用Popup窗口创建无限级Web页菜单(6)    menuObj.__resumeItem();
使用Popup窗口创建无限级Web页菜单(6)};
    这个menuHtml.attachEvent('onmouseout', this.ResumeItem);事件是用来处理鼠标离开了最末级子菜单时,取消菜单条目的选种状态的。随便点开一个系统菜单,把鼠标移到任何一个条目上,该条目就会被highlight,不做任何点击操作,把鼠标移出菜单,该菜单中被highlight的item就会被resume,这个方法就是实现这个效果的。它的关键是判断 !evt || evt.toElement 是否不为真。

    继续说this引用的问题,当这个onmouseout事件被触发时,方法默认的第一个参数是其window上的event,这个我在使用...(3)中说过,还用红色标识出来了的。而这时ResumeItem里的this引用的是当前菜单所在的父IE窗口,所以获得菜单实例的方法仍然是从__MenuCache__里去取(代码中加下划线的语句)。同时除了ResumeItem,所有在AttachEvents里的attach的方法,InnerShow、ActiveItem和Keydown等,里面都不会有对this的调用(除非确实要引用父IE窗口)。 

    to be continued ...

相关文章:

  • 2021-09-16
  • 2021-10-05
  • 2021-06-05
  • 2022-12-23
  • 2021-10-28
  • 2022-12-23
  • 2021-10-14
  • 2021-06-19
猜你喜欢
  • 2021-12-04
  • 2022-01-17
  • 2021-05-22
  • 2021-12-24
  • 2021-07-14
  • 2021-11-12
相关资源
相似解决方案