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

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

    菜单的处理函数Menu.prototype.Keydown是在AttachEvents()方法里通过:
None.gifdoc.attachEvent('onkeydown',  this.Keydown); None.gif
来attach的,为什么要使用onkeydown不用onkeypress呢?是为了让菜单通过键盘快捷键来弹出子菜单时和WinForm方式菜单一样。这个doc是该菜单的popup窗口的doucment对象。

    下面一边看代码一边讲吧:
None.gif     if ( !evt || !evt.srcElement )
None.gif    {
None.gif         return;
None.gif    }
None.gif     var menuBody = evt.srcElement;
None.gif     var menuHtml = FindChildElement(menuBody, 'TABLE');
None.gif     if ( !menuHtml || !menuHtml.uniqueId )
None.gif    {
None.gif        menuHtml = FindParentElement(menuBody, 'TABLE');
None.gif         if ( !menuHtml || !menuHtml.uniqueId )
None.gif        {
None.gif             return;
None.gif        }
None.gif    }
None.gif     var menuObj = __MenuCache__[menuHtml.uniqueId];
None.gif     if ( menuObj.HasSubMenuExpanded() )
None.gif    {
None.gif         return;
None.gif    }
    由于onkeydown事件处理函数attach在document上,所以要得到菜单必须寻找body里面的Table element,不过这个evt.srcElement可能是body,也可能是table的里的元素,关键是看当时菜单popup里的焦点在那个element上。上面代码的最后4句话是判断响应onkeydown事件的菜单是否有子菜单expanded,因为我们只让最后一级显示的子菜单处理keystroke,父级的必须忽略,否则就乱套了。
None.gif     if ( menuObj.m_ShowTimer )
None.gif    {
None.gif        window.clearTimeout(menuObj.m_ShowTimer);
None.gif        menuObj.m_ShowTimer =  null;
None.gif    }
    这是用来支持子菜单显示特效的一个timer,如果手动显示子菜单(包括鼠标click和键盘快捷键),清除这个timer。

None.gif     var activeIndex = -1;
None.gif     for (  var i=0 ; i < menuObj.m_Items.length ; ++i )
None.gif    {
None.gif         if ( menuObj.m_ActiveItem == menuObj.m_Items[i] )
None.gif        {
None.gif            activeIndex = i;
None.gif             break;
None.gif        }
None.gif    }
    把菜单中已active的item的index搜索出来,没有active的menuitem,index为-1。

None.gif     var sign = -1; 
None.gif     switch( evt.keyCode )
None.gif    {
None.gif         case 37 :  //  left
None.gif
        {
None.gif             if ( menuObj.m_ParentMenu )
None.gif            {
None.gif                menuObj.Hide();
None.gif            }
None.gif             break;
None.gif        }
None.gif         case 38 :  //  up | no break;
None.gif
        {
None.gif            sign = 1;
None.gif             if ( activeIndex == -1 )
None.gif            {
None.gif                activeIndex = 0;
None.gif            }
None.gif        }
None.gif         case 40 :  //  down
None.gif
        {
None.gif             var itemCount = menuObj.m_Items.length;
None.gif             for (  var i=1 ; i <= itemCount ; ++i )
None.gif            {
None.gif                 var index = (itemCount+activeIndex-i*sign)%itemCount;
None.gif                 var item = menuObj.m_Items[index];
None.gif                 if ( !item.m_Disabled && item.m_Text != '-' )
None.gif                {
None.gif                    menuObj.__resumeItem();
None.gif                    menuObj.m_ActiveItem = item;
None.gif                    menuObj.__activeItem();
None.gif                     break;
None.gif                }
None.gif            }
None.gif             break;
None.gif        }
None.gif         case 39 :  //  right | no break;
None.gif
        {
None.gif             var activeItem = menuObj.m_ActiveItem; 
None.gif             if ( !activeItem || !activeItem.m_ChildMenu )
None.gif            {
None.gif                 break;
None.gif            }
None.gif        }
None.gif         case 13 :  //  enter
None.gif
        {
None.gif            menuObj.Click();
None.gif             break;
None.gif        }
None.gif         case 27 :
None.gif        {
None.gif             break;
None.gif        }
None.gif    }
    处理left, right, up, down四个键,up和down要麻烦些,因为要查找可用的(separator item和disabled item是不可用的,不能被active)下一个itme来active,到了最有一条itme再同方向up或down还需要有轮转的效果。
    HACK: 由于up和down的代码完全相同,只是搜索方向不同,所以用了一个sign(取值1|-1)标志来判断搜索方向。

None.gif     if ( evt.keyCode >= 48 && evt.keyCode <= 90 )
None.gif    {
None.gif         var keyList = '';
None.gif         var key = String.fromCharCode(evt.keyCode); 
None.gif         for (  var i=0 ; i < menuObj.m_Items.length ; ++i )
None.gif        {
None.gif             var item = menuObj.m_Items[i];
None.gif             if ( !item.m_Disabled && item.m_Mnemonic )
None.gif            { 
None.gif                keyList += item.m_Mnemonic;
None.gif            }
None.gif             else
None.gif            {
None.gif                keyList += '-';
None.gif            }
None.gif        }
None.gif         var index = keyList.indexOf(key); 
None.gif         if ( index != -1 )
None.gif        { 
None.gif             if ( keyList.indexOf(key) == keyList.lastIndexOf(key) )
None.gif            {
None.gif                 if ( !menuObj.m_Items[index].m_Disabled )
None.gif                {
None.gif                    menuObj.__resumeItem(); 
None.gif                    menuObj.m_ActiveItem = menuObj.m_Items[index];
None.gif                    menuObj.__activeItem();
None.gif                    menuObj.Click();
None.gif                }
None.gif            }
None.gif             else
None.gif            {
None.gif                menuObj.__resumeItem();
None.gif                 var newActive;
None.gif                 if ( !evt.shiftKey )
None.gif                {
None.gif                    newActive = keyList.indexOf(key, activeIndex+1);
None.gif                }
None.gif                 else
None.gif                {
None.gif                     if ( activeIndex == 0 )
None.gif                    {
None.gif                        newActive = -1;
None.gif                        index = keyList.lastIndexOf(key);
None.gif                    }
None.gif                     else 
None.gif                    {
None.gif                        newActive = keyList.lastIndexOf(key, activeIndex-1);
None.gif                    }
None.gif                }
None.gif                     
None.gif                 if ( newActive == -1 )
None.gif                {
None.gif                    menuObj.m_ActiveItem = menuObj.m_Items[index];
None.gif                }
None.gif                 else
None.gif                {
None.gif                    menuObj.m_ActiveItem = menuObj.m_Items[newActive];
None.gif                }
None.gif                menuObj.__activeItem();
None.gif            }
None.gif        }
None.gif    }
None.gif
    处理菜单条目上的快捷键Mnemonic,这里的算法是这样的,把该菜单上的每个item上的Mnemonic字符取出组成一个字符串,没有Mnemonic就用'-'代替。比如下面的菜单的Mnemonic字符组成的字符串分别是:
   contextmenu2.gif 
    第一级:"--N---",第二级:"M",第三级:"TTTT"。然后使用String.indexOf(key)就取到被按快捷键的MenuItem的index了,由于没有限制同一个Menu里面多个MenuItem具有相同的Mnemonic,所以像第三级菜单,一直按T键的效果就和按down key一样,它的效果使用语句Sting.indexOf(key, activeIndex+1)来获得。 

ExpandedBlockStart.gif #region 附Menu.prototype.Keydown = function(evt)代码 
None.gifMenu.prototype.Keydown =  function(evt)
None.gif{
None.gif     if ( !evt || !evt.srcElement )
None.gif    {
None.gif         return;
None.gif    }
None.gif     var menuBody = evt.srcElement;
None.gif     var menuHtml = FindChildElement(menuBody, 'TABLE');
None.gif     if ( !menuHtml || !menuHtml.uniqueId )
None.gif    {
None.gif        menuHtml = FindParentElement(menuBody, 'TABLE');
None.gif         if ( !menuHtml || !menuHtml.uniqueId )
None.gif        {
None.gif             return;
None.gif        }
None.gif    }
None.gif     var menuObj = __MenuCache__[menuHtml.uniqueId];
None.gif     if ( menuObj.HasSubMenuExpanded() )
None.gif    {
None.gif         return;
None.gif    }
None.gif
None.gif     if ( menuObj.m_ShowTimer )
None.gif    {
None.gif        window.clearTimeout(menuObj.m_ShowTimer);
None.gif        menuObj.m_ShowTimer =  null;
None.gif    }
None.gif
None.gif     var activeIndex = -1;
None.gif     for (  var i=0 ; i < menuObj.m_Items.length ; ++i )
None.gif    {
None.gif         if ( menuObj.m_ActiveItem == menuObj.m_Items[i] )
None.gif        {
None.gif            activeIndex = i;
None.gif             break;
None.gif        }
None.gif    }
None.gif     var sign = -1; 
None.gif     switch( evt.keyCode )
None.gif    {
None.gif         case 37 :  //  left
None.gif
        {
None.gif             if ( menuObj.m_ParentMenu )
None.gif            {
None.gif                menuObj.Hide();
None.gif            }
None.gif             break;
None.gif        }
None.gif         case 38 :  //  up | no break;
None.gif
        {
None.gif            sign = 1;
None.gif             if ( activeIndex == -1 )
None.gif            {
None.gif                activeIndex = 0;
None.gif            }
None.gif        }
None.gif         case 40 :  //  down
None.gif
        {
None.gif             var itemCount = menuObj.m_Items.length;
None.gif             for (  var i=1 ; i <= itemCount ; ++i )
None.gif            {
None.gif                 var index = (itemCount+activeIndex-i*sign)%itemCount;
None.gif                 var item = menuObj.m_Items[index];
None.gif                 if ( !item.m_Disabled && item.m_Text != '-' )
None.gif                {
None.gif                    menuObj.__resumeItem();
None.gif                    menuObj.m_ActiveItem = item;
None.gif                    menuObj.__activeItem();
None.gif                     break;
None.gif                }
None.gif            }
None.gif             break;
None.gif        }
None.gif         case 39 :  //  right | no break;
None.gif
        {
None.gif             var activeItem = menuObj.m_ActiveItem; 
None.gif             if ( !activeItem || !activeItem.m_ChildMenu )
None.gif            {
None.gif                 break;
None.gif            }
None.gif        }
None.gif         case 13 :  //  enter
None.gif
        {
None.gif            menuObj.Click();
None.gif             break;
None.gif        }
None.gif         case 27 :
None.gif        {
None.gif             break;
None.gif        }
None.gif    }
None.gif     if ( evt.keyCode >= 48 && evt.keyCode <= 90 )
None.gif    {
None.gif         var keyList = '';
None.gif         var key = String.fromCharCode(evt.keyCode); 
None.gif         for (  var i=0 ; i < menuObj.m_Items.length ; ++i )
None.gif        {
None.gif             var item = menuObj.m_Items[i];
None.gif             if ( !item.m_Disabled && item.m_Mnemonic )
None.gif            { 
None.gif                keyList += item.m_Mnemonic;
None.gif            }
None.gif             else
None.gif            {
None.gif                keyList += '-';
None.gif            }
None.gif        }
None.gif         var index = keyList.indexOf(key); 
None.gif         if ( index != -1 )
None.gif        { 
None.gif             if ( keyList.indexOf(key) == keyList.lastIndexOf(key) )
None.gif            {
None.gif                 if ( !menuObj.m_Items[index].m_Disabled )
None.gif                {
None.gif                    menuObj.__resumeItem(); 
None.gif                    menuObj.m_ActiveItem = menuObj.m_Items[index];
None.gif                    menuObj.__activeItem();
None.gif                    menuObj.Click();
None.gif                }
None.gif            }
None.gif             else
None.gif            {
None.gif                menuObj.__resumeItem();
None.gif                 var newActive;
None.gif                 if ( !evt.shiftKey )
None.gif                {
None.gif                    newActive = keyList.indexOf(key, activeIndex+1);
None.gif                }
None.gif                 else
None.gif                {
None.gif                     if ( activeIndex == 0 )
None.gif                    {
None.gif                        newActive = -1;
None.gif                        index = keyList.lastIndexOf(key);
None.gif                    }
None.gif                     else 
None.gif                    {
None.gif                        newActive = keyList.lastIndexOf(key, activeIndex-1);
None.gif                    }
None.gif                }
None.gif                     
None.gif                 if ( newActive == -1 )
None.gif                {
None.gif                    menuObj.m_ActiveItem = menuObj.m_Items[index];
None.gif                }
None.gif                 else
None.gif                {
None.gif                    menuObj.m_ActiveItem = menuObj.m_Items[newActive];
None.gif                }
None.gif                menuObj.__activeItem();
None.gif            }
None.gif        }
None.gif    }
None.gif     if ( evt.keyCode != 27 )
None.gif    {  
None.gif        evt.returnValue =  null;
None.gif        evt.cancelBubble =  true
None.gif    }
None.gif};

     to be continued ...

本文转自博客园鸟食轩的博客,原文链接:http://www.cnblogs.com/birdshome/,如需转载请自行联系原博主。

目录
相关文章
|
存储 IDE 前端开发
SpringBoot2.x系列教程02--新纪元之SpringBoot创建Web项目的常用方式
前言 在上一章节中,壹哥 给大家介绍了SpringBoot的优缺点,并重点介绍了其”约定大于配置“的思想,你现在还能记得吗? 而且上文中,壹哥 说我们创建SpringBoot项目有3种方式,我们已经学习了第一种创建项目的方式了,接下来还有另外两种创建项目的方式,这两种方式该怎么创建项目呢?今天 壹哥 就把剩余的两种方式也一股脑都抖搂给大家吧。 一. 以官网模板方式创建Web项目(了解) 首先 壹哥 给大家介绍第2种创建Web项目的方式,对于这种方式大家仅做了解即可,其原理与第一种以Spring Initializr创建项目的方式一样。 1. 在spring.io官网下载模板构建项目 首先我们
324 0
|
存储 前端开发 JavaScript
【一步步一起学DApp开发】(四)web3.js 基本使用 | 连接geth | 创建web客户端
【一步步一起学DApp开发】(四)web3.js 基本使用 | 连接geth | 创建web客户端
608 0
|
JSON JavaScript 中间件
【node.js从入门到精通】使用express创建web服务器,路由,进行中间件的创建链接路由及其他中间件
【node.js从入门到精通】使用express创建web服务器,路由,进行中间件的创建链接路由及其他中间件
199 1
【node.js从入门到精通】使用express创建web服务器,路由,进行中间件的创建链接路由及其他中间件
|
NoSQL MongoDB 数据库
MongoDB v4.4.6安装、创建服务及Web客户端访问MongoDB详解
MongoDB v4.4.6安装、创建服务及Web客户端访问MongoDB详解
280 0
MongoDB v4.4.6安装、创建服务及Web客户端访问MongoDB详解
|
数据采集 Go
Go Web编程实战(9)----创建客户端
Go Web编程实战(9)----创建客户端
140 1
|
Java Go
Go Web编程实战(8)----创建HTTP与HTTPS服务器端
Go Web编程实战(8)----创建HTTP与HTTPS服务器端
188 0
Go Web编程实战(8)----创建HTTP与HTTPS服务器端
|
JavaScript
【Node.JS 】创建基本的web服务器
【Node.JS 】创建基本的web服务器
158 0
【Node.JS 】创建基本的web服务器
|
Java Maven
IDEA2022版本创建maven web项目(两种方式)
创建maven web项目有两种方式,一种是使用骨架方式,一种是不使用骨架的方式
699 1
IDEA2022版本创建maven web项目(两种方式)
|
Web App开发 XML 开发框架
WebAPI学习(一)——创建Web API程序
WebAPI学习(一)——创建Web API程序
249 0
|
JavaScript 前端开发
Node.js 创建并封装静态 WEB 服务器
Node.js 创建并封装静态 WEB 服务器
123 0
Node.js 创建并封装静态 WEB 服务器