您可能不知道,HTML5 规范不仅限于我们在页面中添加的内容,还定义了浏览器的一些部分如何通过 HTML、CSS 和 JavaScript 供开发者使用。这些规范中的一部分是 上下文菜单,或“右键菜单”。使用 HTML5 和菜单元素,您可以添加新的选项,而无需编写浏览器插件。Firefox 8(当前版本)支持这些功能。请查看以下屏幕截图以了解 上下文菜单演示。
图像示例非常简单,实际上是由 Paul Rouget 编写的一个演示 在最初的 Firefox 错误请求中。其核心是 HTML 代码
如您所见,您可以通过其 ID 将 menu
元素链接到一个元素。contextmenu
属性指向此元素。每个菜单可以有多个 menuitems
。每个项目都有一个文本标签和一个可能的图标。您还可以嵌套 menu
元素以创建多层菜单。在这里,我们添加内联
功能很简单,所有 rotate()
和 resize()
函数所做的就是使用 querySelector
和 classList
向图像添加类名
function rotate() {
document.querySelector('#menudemo').classList.toggle('rotate');
}
function resize() {
document.querySelector('#menudemo').classList.toggle('resize');
}
真正的效果在于 CSS 变换和过渡。由于图像的 ID 为 menudemo
,因此在 CSS 中需要以下代码来旋转和调整大小
#menudemo {
-moz-transition: 0.2s;
width:200px;
}
#menudemo.rotate {
-moz-transform: rotate(90deg);
}
#menudemo.resize {
-moz-transform: scale(0.7);
}
#menudemo.resize.rotate {
-moz-transform: scale(0.7) rotate(90deg);
}
请注意,在实际产品中,我们当然应该添加其他浏览器前缀并取消前缀,但由于该功能目前仅在 Firefox 中有效,因此对于此演示来说足够了。
检测支持和视觉提示
现在,由于这扩展了浏览器中正常的用户功能,因此我们需要明确指出存在一个右键菜单。在 CSS3 中,有一个 context-menu
光标可供我们使用。当上下文菜单可用时,应显示此光标
.contextmenu #menudemo, .contextmenu .demo {
cursor: context-menu;
}
我们通过检查 body 元素上的 contextmenu 和窗口中的 HTMLMenuItemElement
来测试浏览器的支持(这也已作为拉取请求添加到 Modernizr 中)。
if ('contextMenu' in document.body && 'HTMLMenuItemElement' in window) {
document.documentElement.classList.add('contextmenu');
} else {
return;
}
HTMLMenuItemElement
不够吗?是的,但真正的上下文菜单仅在合理的情况下提供功能,这就是 contextMenu
发挥作用的地方。
根据功能打开或关闭菜单项
作为一个稍微复杂一点的示例,让我们向文档中添加“统计字数”功能。为此,我们生成一个计数器元素,当统计完字数时,它将成为一个工具提示
var counter = document.createElement('span');
counter.id = 'counter';
counter.className = 'hide';
document.body.appendChild(counter);
counter.addEventListener('click', function(ev){
this.className = 'hide';
},false);
默认情况下隐藏此元素,并在删除 hide
类时显示。为了使其平滑,我们使用过渡
#counter{
position: absolute;
background: rgba(0,0,0,0.7);
padding:.5em 1em;
color: #fff;
font-weight:bold;
border-radius: 5px;
-moz-transition: opacity 0.4s;
}
#counter.hide{
opacity: 0;
}
我们从两个带有上下文菜单的部分开始
然后,我们循环遍历所有具有 wordcount
类的 menuitems
并应用功能。
var wordcountmenus = document.querySelectorAll('.wordcount'),
i = wordcountmenus.length;
while (i--) {
wordcountmenus[i].addEventListener('click', function(ev){
// add functionality
}, false);
}
我们需要找出页面中选择了什么。我们通过使用 getSelection()
并将其字符串版本在空格处拆分来实现。然后,我们通过删除 hide
类名来显示计数器。
var wordcountmenus = document.querySelectorAll('.wordcount'),
i = wordcountmenus.length;
while (i--) {
wordcountmenus[i].addEventListener('click', function(ev){
var text = document.getSelection(),
count = text.toString().split(/s/).length;
counter.innerHTML = count + ' words';
counter.className = '';
}, false);
}
您可以在第二个 上下文菜单演示 中看到它的实际效果。现在,问题在于(如屏幕截图中所述),它始终统计字数,而不管用户是否选择了某些文本。我们希望菜单仅在选择了文本时处于活动状态。
因此,为了使我们的菜单仅在有意义时才可用,我们检查文档中是否存在选择。每个上下文菜单在打开时都会触发一个名为 contextmenu
的事件。因此,我们只需要订阅此事件即可。
当文档中选择了某些内容时,document.getSelection().isCollapsed
为 true。否则为 false,因此我们只需要相应地启用或禁用菜单项即可
document.querySelector('#interactive').addEventListener(
'contextmenu', function(ev) {
this.querySelector('.wordcount').disabled =
document.getSelection().isCollapsed;
},
false);
最后一个要解决的问题是鼠标的位置,以便放置计数器元素。由于菜单选择事件没有提供鼠标位置,因此我们需要向整个文档添加一个 contextmenu
处理程序,以便在打开菜单时将计数器隐藏在菜单后面
document.body.addEventListener(
'contextmenu', function(ev) {
counter.style.left = ev.pageX + 'px';
counter.style.top = ev.pageY + 'px';
counter.className = 'hide';
},
false);
进一步阅读和资源
关于 Chris Heilmann
HTML5 和开放网络的布道者。让我们修复它!
19 条评论