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

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

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

ContractedBlock.gifExpandedBlockStart.gifCreateMenu#region CreateMenu
InBlock.giffunction CreateContextMenu()
InBlock.gif{
InBlock.gif    
var menu = new Menu();
InBlock.gif    
for ( var i=1 ; i < 6 ; i++ )
InBlock.gif    {
InBlock.gif         
var mi = new MenuItem('Menu Item 1-+ i, Alert);
InBlock.gif         menu.Add(mi);
InBlock.gif    }
InBlock.gif    
var submenu = new Menu();
InBlock.gif    
for ( var i=1 ; i < 5 ; i++ )
InBlock.gif    {
InBlock.gif         
var mi = new MenuItem('Menu I&tem 3-+ i, Alert);
InBlock.gif         submenu.Add(mi); 
InBlock.gif    }
InBlock.gif    
var submenu2 = new Menu();
InBlock.gif    submenu2.Add(
new MenuItem('&Menu Item 2-1', nullnullnull, submenu));
InBlock.gif    
var mi2 = new MenuItem('Me&nu Item 1-6', Alert, 'images/paste.small.png', null, submenu2);
InBlock.gif    menu.AddAt(mi2, 
2);
InBlock.gif    
return menu;
InBlock.gif}

ExpandedBlockEnd.gif
#endregion
</script>
   contextmenu2.gif   

生成的Context Menu效果


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

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

None.gif    w 
= this.__isEllipsis(this, menuHtml);
None.gif    
var h = popdoc.body.scrollHeight;
None.gif    
var x = win.event.clientX + win.screenLeft;
None.gif    
var y = win.event.clientY + win.screenTop;
None.gif    popup.show(x, y, w, h); 
      // 菜单的显示特效,使用filter实现的
None.gif    
this.FadeinEffect(Menu.Attributes.ShowMenuEffect);
None.gif    menuObj.m_Bounds 
= 
None.gif    {
None.gif        top: x, left: y,
None.gif        width: menuHtml.offsetWidth,
None.gif        height: menuHtml.offsetHeight
None.gif    }; 
      // 把菜单操作的事件attach到菜单上,鼠标和键盘操作等
None.gif    menuObj.AttachEvents(menuHtml);
None.gif};
    上面注解应该都比较清楚了,只是这个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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/305902.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【gRPC】ProtoBuf 语言快速学习指南

继上篇【gRPC】 在.Net core中使用gRPC了解了gRPC的使用&#xff0c;gRPC基于HTTP/2和ProtoBuf&#xff0c;ProtoBuf就非常有必要好好了解一下了&#xff0c;那么ProtoBuf究竟是什么&#xff1f;ProtoBuf Google Protocol Buffer是一种语言无关、平台无关、可扩展的序列化结构数…

vspythonqt混合_PYQT5 vscode联合操作qtdesigner的方法

除了使用pycharm外&#xff0c;还可使用vscode来操作pyqt&#xff0c;方法如下&#xff1a;1. 在vscode中配置相关的pyqt的相关根据自己实际情况修改第一项pyqt的路径2. 创建一个文件夹&#xff0c;右键&#xff0c;最后一项可以创建一个新窗口创建的新窗口后缀为 .ui右键中有以…

TIOBE 1 月榜单:Python年度语言四连冠,C 语言再次第一

喜欢就关注我们吧&#xff01;TIOBE 公布了 2021 年 1 月的编程语言排行榜。TIOBE 本月公布了 2020 年度编程语言&#xff0c;Python 获得四连冠&#xff0c;是过去一年中最受欢迎的编程语言。Python 在 2020 年实现了 2.01&#xff05; 的正增长&#xff1b;C 紧随其后&#x…

A piecture of J2EE Core Patterns

这张图是J2EE Core Patterns里面的一幅图片,在Enterprise Solution Patterns Using Microsoft.Net里面虽然模式的概念与应用大同小异&#xff0c;但是那张表现架构模式整体的图感觉有点不直观,相比之下这幅图显得更清晰一点。 发到这里供大家参考学习&#xff1a;&#xff09…

孙丕恕离开浪潮 仪器厂历时60年成为服务器龙头企业

2020年12月31日浪潮集团有限公司董事会选举邹庆忠为公司董事长&#xff08;法定代表人&#xff09;&#xff1b;孙丕恕不再担任公司董事长&#xff1b;公司不再聘任孙丕恕为首席执行官。另外&#xff0c;经省委研究决定&#xff0c;拟任省直部门&#xff08;单位&#xff09;副…

java 数组 树_java使用顺序数组实现二叉树

顺序数组实现二叉树实现原理对于下标为index的节点其满足1.左孩子节点的下标为2index12.右孩子节点的下标为2index2代码实现package tree;public class ArrayBinaryTree {private int[] arr;public ArrayBinaryTree(int[] arr){this.arrarr;}public void preOrder(int index){i…

【Docker】Asp.net core在docker容器中的端口问题

还记得【One by one系列】一步步学习docker&#xff08;三&#xff09;——实战部署dotnetcore中遇到的问题么&#xff1f;容器内部启动始终是80端口&#xff0c;并不由命令左右。docker run --name container-name -p 81:5000 mywebapi所谓知其然就要知其所以然&#xff0c;浅…

.net 5.0 中的 JsonConsole

asp.net core 5.0 中的 JsonConsoleIntroasp.net core 5.0 中日志新增了 JsonConsole&#xff0c;还是输出日志到 Console&#xff0c;但是会应用 Json 格式的一个 Formatter 把日志格式化成 json 再输出到控制台Sample一起来看一个示例&#xff0c;以我的一个小项目为例子来演…

采用开源软件搭建WebGIS系统(6)数据格式

[本文版权由xiaotievip.sina.com所有&#xff0c;转载需得到作者同意。] 在国家基础地理信息中心下载到的数据格式是Shape file数据。Shape file数据由3个文件构成&#xff0c;*.shp&#xff0c;*.dbf和*.shx&#xff0c;分别存储空间数据、属性数据和两者间的关系。*.shp得专门…

.NET Core 使用Topshelf方式创建Windows服务

Topshelf是一个.NET Standard库&#xff0c;它消除了在.NET Framework和.NET Core中创建Windows服务的那些麻烦。安装Install-Package Topshelf代码using System; using System.Collections.Generic; using System.Text; using Topshelf;namespace ConsoleApp2222 {public clas…

Roslyn 使用 Directory.Build.props 管理多个项目配置

在一些大项目需要很多独立的仓库来做&#xff0c;每个仓库之间都会有很多相同的配置&#xff0c;本文告诉大家如何通过 Directory.Build.props 管理多个项目配置在我的 MVVM 框架需要三个不同的库&#xff0c;一个是 Framework 另外两个是 WPF 和 UWP 这三个库有很多重复的配置…

java 中符号_谁能告诉我java中符号的用法,见代码

展开全部大家都知道Vector以及其他的容器可以不加任何修饰地e68a8462616964757a686964616f31333236373765存储任何类型的对象,这给我们带来了极大的方便&#xff0c;也使得容器很容易被复用&#xff0c;但是大多数时候我们可能需要只能存储某一类型对象的Vector&#xff0c;这是…

在.NET Core中使用Channel(一)

我最近一直在熟悉.net Core中引入的新Channel<T>类型。我想在它第一次发布的时候我了解过它&#xff0c;但是有关文章非常非常少&#xff0c;我不能理解它们与其他队列有什么不同。在使用了一段时间后&#xff0c;我终于看到了它们的吸引力和真正的力量。最值得注意的是大…

java控制系统音量_Java 控制 Windows 系统音量-Go语言中文社区

目录1、使用 Java 来控制 Windows 系统音量&#xff0c;使用 JNA 调用 windows 底层 API 因为有点麻烦&#xff0c;所以这里采用纯 Java API结合 VBS 脚本的方式进行控制。2、可以参考《VBS 控制 Windos 系统音量 及视频播放》&#xff0c;本文同样是利用 VBS 来控制&#xff0…

【Hook】postman工具的代码生成工具让它锦上添花

修改postman工具的代码生成工具加入response自动生成POJO代码如上图可以快速把请求这个动作转成code&#xff0c;减少重复性劳动。但是有一点我觉得可以优化下 就是返回的json如果也能自动转成代码就好了。不然在需要把json序列化成java或者csharp的POJO对象时还得自己coding转…

使用BeetleX.ESDoc构建文档搜索功能

BeetleX.ESDoc组件是基于ElasticSearch服务的文档搜索扩展组件。它在BeetleX.Elasticsearch的基础上包装一些基于文档检索的功能和方法&#xff0c;可以让你在不了解ElasticSearch API的情况下直接存储&#xff0c;删除和搜索相关信息。信息结构BeetleX.ESDoc定义了一个基础的文…

日产汽车源码遭泄露

喜欢就关注我们吧&#xff01;日产北美公司开发和使用的移动应用及内部工具的源代码于近日在网上泄露&#xff0c;原因是该公司错误配置了其中一台 Git 服务器。瑞士软件工程师 Tillie Kottmann 向 ZDNet 透露&#xff0c;此次泄露源于一台配置错误的 Bitbucket Git 服务器的信…

中台的故事结束了?

大家好&#xff0c;我是Z哥。所谓30年河东30年河西&#xff0c;最近阿里开始去中台了。这是不是意味着中台时代的落幕&#xff0c;去中心化时代的开始&#xff1f;谁都说不准。但是我们可以来思考一下这个事情背后释放出了什么样的信号。对我们普通人&#xff0c;特别是互联网行…

java树算法_Java数据结构算法(三)树

本文旨作于收集整理使用&#xff01;&#xff01;导航一、树树(Tree)是n(n≥0)个结点的有限集&#xff0c;n0称之为空树。在非空树种&#xff1a;当有且仅有一个特定的称为根(Root)的结点&#xff1b; 其余结点可以划分为m(m&#xff1e;0)个互不相交的有限集T1、T2 、…、Tm&a…

Blazor VS 传统Web应用程序

原文作者: Christian Findlay原文链接&#xff1a;https://christianfindlay.com/2020/07/09/blazor-vs-traditional-web-apps/Blazor是Microsoft团队开发的单页面应用程序&#xff08;SPA&#xff09;框架&#xff0c;它是与React&#xff0c;Angular和Vue.js有相同之处&#…