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

为了比较直观的说明代码的作用,我就从菜单的显示开始说。要显示一个菜单显必须构建一个菜单的实例,实例构建的完整代码如下:

<div oncontextmenu="return ShowContextMenu(this);" style="width: 200; height: 200; border: solid 1px blue;">
    <table width="100%" height="100%" border="0">
         <tr>
             <td valign="middle" align="center">
                  right click me
             </td>
         </tr>
    </table>
</div>
<script language="javascript">
function ShowContextMenu(elmt)
{
    if ( !elmt.contextMenu )
    {
         elmt.contextMenu = CreateContextMenu();
    }
    var win = window; 
    elmt.contextMenu.Show(win);
    return false; 
}
CreateMenu#region CreateMenu
function CreateContextMenu()
{
    var menu = new Menu();
    for ( var i=1 ; i < 6 ; i++ )
    {
         var mi = new MenuItem('Menu Item 1-' + i, Alert);
         menu.Add(mi);
    }
    var submenu = new Menu();
    for ( var i=1 ; i < 5 ; i++ )
    {
         var mi = new MenuItem('Menu I&tem 3-' + i, Alert);
         submenu.Add(mi); 
    }
    var submenu2 = new Menu();
    submenu2.Add(new MenuItem('&Menu Item 2-1', null, null, null, submenu));
    var mi2 = new MenuItem('Me&nu Item 1-6', Alert, 'images/paste.small.png', null, submenu2);
    menu.AddAt(mi2, 2);
    return menu;
}
#endregion
</script>
      

生成的Context Menu效果

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

我们现在来看这个Menu.prototype.Show(win)方法,这是菜单的第一级显示时的方法,它是由用户来调用的,因为菜单需要定位于用户给定位置(ContextMenu的用户给定位置就是鼠标点击的位置)。在菜单显示出第一级后,后续的子菜单的显示,都是在Menu类内部来处理的,子菜单位置是相对于parent menu,后续逻辑就都封装在Menu类内部了。Show()方法代码如下:

Menu.prototype.Show = function(win)
{
    if ( !win )
    {
        return;
    }
    var menuObj = this;
    menuObj.m_Opener = win;
    menuObj.__resumeItem();
    var win = menuObj.m_Opener;
    var popup, popwin, popdoc;
    // 判断菜单的容器popup是否建立
    if ( !menuObj.m_Popup )
    {
        popup = win.createPopup();
        popup.document.body.bgColor = 'windowtext';
        popup.document.body.style.backgroundColor = 'window';
        menuObj.m_Popup = popup;
    }
    else
    {
        popup = menuObj.m_Popup;
        menuObj.__resumeAll();
    }
    popdoc = popup.document;
    popwin = popdoc.parentWindow;
    // 判断是否需要重绘菜单的内容
    if ( menuObj.m_Invalidate || !menuObj.m_Drawn )
    {
        popdoc.body.innerHTML = menuObj.Render().outerHTML;
        // popdoc.body.appendChild(menuObj.Render());
        menuObj.m_Invalidate = false;
        menuObj.m_Drawn = true;
    }
    // 获取菜单的主table(菜单是使用table来实现的)
    var menuHtml = popup.document.getElementById('menu');
    // 这个show只是为了测量菜单的bounds而调用的
    popup.show(0, 0, 1, 1);
    var w = popdoc.body.scrollWidth; 
      // 判断菜单条目的Text的显示宽度是否在许可范围内,
      // 如果超出许可范围则ellipsis处理并返回新的MenuItem的width
    w = this.__isEllipsis(this, menuHtml);
    var h = popdoc.body.scrollHeight;
    var x = win.event.clientX + win.screenLeft;
    var y = win.event.clientY + win.screenTop;
    popup.show(x, y, w, h); 
      // 菜单的显示特效,使用filter实现的
    this.FadeinEffect(Menu.Attributes.ShowMenuEffect);
    menuObj.m_Bounds = 
    {
        top: x, left: y,
        width: menuHtml.offsetWidth,
        height: menuHtml.offsetHeight
    }; 
      // 把菜单操作的事件attach到菜单上,鼠标和键盘操作等
    menuObj.AttachEvents(menuHtml);
};

上面注解应该都比较清楚了,只是这个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 ...

转载于:https://www.cnblogs.com/birdshome/archive/2004/12/17/78200.html

使用Popup窗口创建无限级Web页菜单(5)相关推荐

  1. 使用Popup窗口创建无限级Web页菜单(7)

    这一节主要说一下Menu对键盘的支持,本来不支持键盘这个菜单也完全可用了,不过还是为了和WinForm的Menu统一,所以支持了和WinForm菜单一样的操作方式. 菜单的处理函数Menu.proto ...

  2. php创建无限级树型菜单以及三级联动菜单

    http://www.php.cn/php-weizijiaocheng-373500.html 这篇文章主要介绍了php创建无限级树型菜单 ,主要使用的是递归函数,感兴趣的小伙伴们可以参考一下 写递 ...

  3. php动态创建菜单,php创建无限级树型菜单

    写递归函数,可考虑缓存,定义一些静态变量来存上一次运行的结果,多程序运行效率很有帮助.. 大概步骤如下: step1:到数据库取数据,放到一个数组, step2:把数据转化为一个树型状的数组, ste ...

  4. php通用的树型类创建无限级树型菜单

    生成树型结构所需要的2维数组,var $arr = array()数组格式如下: array( 1 => array('id'=>'1','parentID'=>0,'name'=& ...

  5. Popup窗口在XP+SP2下面受到限制

    在微软XP SP2对IE6兼容性的官方文档<Compatibility in Internet Explorer 6 for Windows XP Service Pack 2>中,微软口 ...

  6. 在popup窗口中俘获事件的缺陷修复

    我们在处理HTML元素的事件时,通常可以使用两种方法来添加其处理函数.一是直接向HTML元素的事件处理回调(如:onclick.onlond等)赋值:一是使用元素的attachEvent()方法来添加 ...

  7. 使用window.createPopup创建无限级跨帧下拉菜单

    我的BLOG搬家到自己的站点了 站点链接 RSS   先帖样子      使用层或者其他技术所实现的JS菜单不能解决的问题就是这些菜单不能跨帧,也就是说在Frame之间的时候无可奈何,所幸的是IE5+ ...

  8. c语言怎样响应右键弹出窗口,MFC创建右键弹出菜单的方法

    本文实例讲述了MFC创建右键弹出菜单的方法.分享给大家供大家参考.具体实现方法如下: ①.添加一个菜单资源,ID为IDM_RIGHTMENU.因为在显示右键菜单时顶级菜单是不显示的,所以可以给它设置任 ...

  9. idea的几个好用快捷键、常用配置(包括git)、jdk和javaSE和javaEE、创建一个SE工程、debug、创建一个Web工程、打war包

    几个好用的快捷键(持续更新) Ctrl+Shift+f12 ,相当于myeclipse的ctrl+m 最大化窗口的 alt+shift+↑或↓,将当前行上移或下移 shift+enter ,当前行下一 ...

最新文章

  1. 通过XML文件生成View
  2. 在python中等号前面与后面分别是什么意思-Python中%是什么意思?python中百分号如何使用?...
  3. 驾照考试:六百公里考试流程与注意事项
  4. Oracle Study案例之--基于表空间的时间点恢复(TSPITR)
  5. markdown 编辑器_Markdown 编辑器使用指南
  6. 一文教你如何在生产环境中在Kubernetes上部署Jaeger
  7. java对象转JSON JS取JSON数据
  8. 解决linux系统WIFI无法使用5GHz频率的问题
  9. 关于Cocos2d-x的粒子系统
  10. Web性能测试篇:AB 压力测试
  11. CleanMyMac X2021专业苹果电脑系统优化工具
  12. “智慧城市”建设为何需要“顶层设计”
  13. PROFINET非周期数据通信详解
  14. VirtualBox虚拟机安装Windows XP
  15. JavaScript实现富文本编辑器
  16. 【转】布同:如何循序渐进学习Python语言
  17. python中用来返回序列的最大函数_Python内置函数____________用来返回序列中的最大元素。...
  18. NIO和BIO和AIO区别
  19. 什么是天气预报 API 接口?如何获取天气预报 API?
  20. Arduino之干接点控制继电器取反实例

热门文章

  1. GetDisplayName 获取枚举的显示值
  2. 飞了,飞了,真的疯了
  3. linux查看python环境变量_Linux中添加PYTHONPATH配置anaconda环境变量方法
  4. androidsdk里的android.bat和uiautomatorview.bat启动就闪退问题
  5. windows 安装yaml支持和pytest支持等
  6. Linux中写入ISO镜像
  7. linux下安装配置DHCP服务器
  8. Rails 开发小贴士积累
  9. [9月29日的脚本] 枚举SharePoint列表(PowerShell)
  10. Android网络通信的六种方式示例代码