我需要检测上下文菜单何时关闭,因此我想出了一个解决方案。
小提琴: https ://jsfiddle.net/kexp0nmd/1/
var premenuelem;
var TempContextMenuCloseHandler = function(e) {
console.log('closed!');
//console.log(e);
window.removeEventListener('keyup', TempContextMenuCloseHandler, true);
window.removeEventListener('mousedown', TempContextMenuCloseHandler, true);
window.removeEventListener('focus', TempContextMenuCloseHandler, true);
var focuselem = document.getElementById('tempfocus');
if (focuselem === document.activeElement) premenuelem.focus();
focuselem.style.display = 'none';
};
var TempContextMenuHandler = function(e) {
console.log('open!');
//console.log(e);
premenuelem = document.activeElement;
var focuselem = document.getElementById('tempfocus');
focuselem.style.display = 'block';
focuselem.focus();
window.addEventListener('keyup', TempContextMenuCloseHandler, true);
window.addEventListener('mousedown', TempContextMenuCloseHandler, true);
window.addEventListener('focus', TempContextMenuCloseHandler, true);
};
window.addEventListener('contextmenu', TempContextMenuHandler, true);
html, body { min-height: 100%; }
<textarea></textarea>
<div id="tempfocus" tabIndex="-1" style="left: 0; bottom: 0; height: 50px; width: 100%; background-color: #CCCCCC; display: none; position: fixed; outline: none;"></div>
截至 2020 年 5 月,已在 Edge、Firefox 76 和 Chrome 80 的鼠标和键盘上进行测试和验证。移动/触摸支持未知。
该解决方案的关键方面是使用一个带有 a 的元素tabIndex
。通过在上下文菜单出现之前显示并将焦点移动到该元素(焦点窃取),会导致 Edge 和 Chrome 在用户稍后关闭上下文菜单时发送焦点更改事件。我将 div 的背景设置为灰色,以便可以看到 - 在生产中,将其设置为透明背景并根据需要设置样式。
当keyup
键盘关闭上下文菜单时,处理程序捕获 Escape/Enter 键的释放。该mousedown
处理程序仅在 Firefox 中捕获 mousedown 事件。
据我所知,无法确定用户选择了哪个选项,或者即使他们确实选择了一个选项。至少,它允许在所有主要浏览器中一致地检测上下文菜单打开/关闭。
示例中的 textarea 只是为了提供其他可用于焦点处理的内容。
虽然此解决方案涉及临时焦点窃取,但它是最干净的跨浏览器解决方案,直到浏览器供应商和 W3C 向 DOM 添加“exitcontextmenu”事件或类似事件。
我刚刚遇到的一个小错误:显示上下文菜单并切换到另一个应用程序会关闭上下文菜单,但不会立即触发关闭事件。但是,在切换回 Web 浏览器时,会触发事件并运行关闭处理程序。向窗口添加“模糊”捕获可能会解决这个问题,但我必须重新测试所有内容,它可能会破坏某些东西(例如打开上下文菜单时的火焰模糊)。在极少数情况下可能会发生这种情况并且处理程序仍然会触发,因此不值得修复 - 它只是明显延迟了。