代码框架在(4)里面已经全部列出来了,现在工作就是按流程把他们完成。本来实现一个prototype的Menu菜单类只需要最多300行代码,可是后来做了一些操作习惯支持和UI显示上的优化后,代码猛增到了1000多行。不过final版本看起来确实比土不拉叽的prototype强很多哦使用Popup窗口创建无限级Web页菜单(5)

    为了比较直观的说明代码的作用,我就从菜单的显示开始说。要显示一个菜单显必须构建一个菜单的实例,实例构建的完整代码如下:
使用Popup窗口创建无限级Web页菜单(5)<div oncontextmenu="return ShowContextMenu(this);" style="width: 200; height: 200; border: solid 1px blue;">
使用Popup窗口创建无限级Web页菜单(5)    
<table width="100%" height="100%" border="0">
使用Popup窗口创建无限级Web页菜单(5)         
<tr>
使用Popup窗口创建无限级Web页菜单(5)             
<td valign="middle" align="center">
使用Popup窗口创建无限级Web页菜单(5)                  right click me
使用Popup窗口创建无限级Web页菜单(5)             
</td>
使用Popup窗口创建无限级Web页菜单(5)         
</tr>
使用Popup窗口创建无限级Web页菜单(5)    
</table>
使用Popup窗口创建无限级Web页菜单(5)
</div>
使用Popup窗口创建无限级Web页菜单(5)<script language="javascript">
使用Popup窗口创建无限级Web页菜单(5)function ShowContextMenu(elmt)
使用Popup窗口创建无限级Web页菜单(5){
使用Popup窗口创建无限级Web页菜单(5)    
if ( !elmt.contextMenu )
使用Popup窗口创建无限级Web页菜单(5)    {
使用Popup窗口创建无限级Web页菜单(5)         elmt.contextMenu 
= CreateContextMenu();
使用Popup窗口创建无限级Web页菜单(5)    }
使用Popup窗口创建无限级Web页菜单(5)    
var win = window; 
使用Popup窗口创建无限级Web页菜单(5)    elmt.contextMenu.Show(win);
使用Popup窗口创建无限级Web页菜单(5)    
return false
使用Popup窗口创建无限级Web页菜单(5)}

>
   使用Popup窗口创建无限级Web页菜单(5)   

生成的Context Menu效果


    这是完全手工添加菜单条目生成的一个Context Menu,最后会完成一个自动解析菜单数据来生成菜单的方法。

    我们现在来看这个Menu.prototype.Show(win)方法,这是菜单的第一级显示时的方法,它是由用户来调用的,因为菜单需要定位于用户给定位置(ContextMenu的用户给定位置就是鼠标点击的位置)。在菜单显示出第一级后,后续的子菜单的显示,都是在Menu类内部来处理的,子菜单位置是相对于parent menu,后续逻辑就都封装在Menu类内部了。Show()方法代码如下:
使用Popup窗口创建无限级Web页菜单(5)Menu.prototype.Show = function(win)
使用Popup窗口创建无限级Web页菜单(5){
使用Popup窗口创建无限级Web页菜单(5)    if ( !win )
使用Popup窗口创建无限级Web页菜单(5)    {
使用Popup窗口创建无限级Web页菜单(5)        
return;
使用Popup窗口创建无限级Web页菜单(5)    }
使用Popup窗口创建无限级Web页菜单(5)    
var menuObj = this;
使用Popup窗口创建无限级Web页菜单(5)    menuObj.m_Opener 
= win;
使用Popup窗口创建无限级Web页菜单(5)    menuObj.__resumeItem();
使用Popup窗口创建无限级Web页菜单(5)    
var win = menuObj.m_Opener;
使用Popup窗口创建无限级Web页菜单(5)    
var popup, popwin, popdoc;
使用Popup窗口创建无限级Web页菜单(5)    
// 判断菜单的容器popup是否建立
使用Popup窗口创建无限级Web页菜单(5)
    if ( !menuObj.m_Popup )
使用Popup窗口创建无限级Web页菜单(5)    {
使用Popup窗口创建无限级Web页菜单(5)        popup 
= win.createPopup();
使用Popup窗口创建无限级Web页菜单(5)        popup.document.body.bgColor 
= 'windowtext';
使用Popup窗口创建无限级Web页菜单(5)        popup.document.body.style.backgroundColor 
= 'window';
使用Popup窗口创建无限级Web页菜单(5)        menuObj.m_Popup 
= popup;
使用Popup窗口创建无限级Web页菜单(5)    }
使用Popup窗口创建无限级Web页菜单(5)    
else
使用Popup窗口创建无限级Web页菜单(5)    {
使用Popup窗口创建无限级Web页菜单(5)        popup 
= menuObj.m_Popup;
使用Popup窗口创建无限级Web页菜单(5)        menuObj.__resumeAll();
使用Popup窗口创建无限级Web页菜单(5)    }
使用Popup窗口创建无限级Web页菜单(5)    popdoc 
= popup.document;
使用Popup窗口创建无限级Web页菜单(5)    popwin 
= popdoc.parentWindow;
使用Popup窗口创建无限级Web页菜单(5)    
// 判断是否需要重绘菜单的内容
使用Popup窗口创建无限级Web页菜单(5)
    if ( menuObj.m_Invalidate || !menuObj.m_Drawn )
使用Popup窗口创建无限级Web页菜单(5)    {
使用Popup窗口创建无限级Web页菜单(5)        popdoc.body.innerHTML 
= menuObj.Render().outerHTML;
使用Popup窗口创建无限级Web页菜单(5)        
// popdoc.body.appendChild(menuObj.Render());
使用Popup窗口创建无限级Web页菜单(5)
        menuObj.m_Invalidate = false;
使用Popup窗口创建无限级Web页菜单(5)        menuObj.m_Drawn 
= true;
使用Popup窗口创建无限级Web页菜单(5)    }
使用Popup窗口创建无限级Web页菜单(5)    
// 获取菜单的主table(菜单是使用table来实现的)
使用Popup窗口创建无限级Web页菜单(5)
    var menuHtml = popup.document.getElementById('menu');
使用Popup窗口创建无限级Web页菜单(5)    
// 这个show只是为了测量菜单的bounds而调用的
使用Popup窗口创建无限级Web页菜单(5)
    popup.show(0011);
使用Popup窗口创建无限级Web页菜单(5)    
var w = popdoc.body.scrollWidth; 
      // 判断菜单条目的Text的显示宽度是否在许可范围内,
      // 如果超出许可范围则ellipsis处理并返回新的MenuItem的width

使用Popup窗口创建无限级Web页菜单(5)    w 
= this.__isEllipsis(this, menuHtml);
使用Popup窗口创建无限级Web页菜单(5)    
var h = popdoc.body.scrollHeight;
使用Popup窗口创建无限级Web页菜单(5)    
var x = win.event.clientX + win.screenLeft;
使用Popup窗口创建无限级Web页菜单(5)    
var y = win.event.clientY + win.screenTop;
使用Popup窗口创建无限级Web页菜单(5)    popup.show(x, y, w, h); 
      // 菜单的显示特效,使用filter实现的
使用Popup窗口创建无限级Web页菜单(5)    
this.FadeinEffect(Menu.Attributes.ShowMenuEffect);
使用Popup窗口创建无限级Web页菜单(5)    menuObj.m_Bounds 
= 
使用Popup窗口创建无限级Web页菜单(5)    {
使用Popup窗口创建无限级Web页菜单(5)        top: x, left: y,
使用Popup窗口创建无限级Web页菜单(5)        width: menuHtml.offsetWidth,
使用Popup窗口创建无限级Web页菜单(5)        height: menuHtml.offsetHeight
使用Popup窗口创建无限级Web页菜单(5)    }; 
      // 把菜单操作的事件attach到菜单上,鼠标和键盘操作等
使用Popup窗口创建无限级Web页菜单(5)    menuObj.AttachEvents(menuHtml);
使用Popup窗口创建无限级Web页菜单(5)};
    上面注解应该都比较清楚了,只是这个popup.show(0, 0, 1, 1);比较有意思哈,当我们向popup里添加好了菜单的HTML元素后,我们发现在popup没有显示过之前,是根本取不到构成Menu UI的那个Table element的bounds信息的。这里show上一下后,就是为了让IE算出其bounds信息,然后再使用实际的bounds信息show菜单。这算一个小hack吧,也是这个Menu中比较有效率的地方,因为除了这个show(0, 0, 1,1)就在没有计算菜单bounds的地方了,当然也用不着了。然而为什么又没有把bounds计算也做成lazy load象popup的生成那样呢?是因为用户可能在菜单显示后修改IE的字体大小(比如按住Ctrl再滚动鼠标滚轮),这样保证了再次显示菜单时能修正菜单的实际bounds。而后面把menu的bounds存了起来是为了在显示子菜单时,方便判断其默认向右展开空间是否足够,如果不够宽则从parent menu左侧展开。 

    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-07-13
相关资源
相似解决方案