如何禁用上下文菜单中止的所有单击操作?

时间:2014-04-01 22:09:11

标签: javascript

我们有自定义上下文菜单,可以在右键单击时替换浏览器菜单。我们希望能够以与浏览器隐藏默认上下文菜单相同的方式中止(隐藏)上下文菜单 - 单击菜单外的任何位置未注册为单击。该解决方案应该适用于绑定事件和默认浏览器操作,但不会妨碍其他事件的能力,即。 hover来自解雇。

示例

在Firefox中,右键单击此页面以打开上下文菜单。将鼠标悬停在

Questions-Tags-Users-Badges-Unanswered

位于此页面顶部。即使上下文菜单已打开,仍会出现突出显示。现在,单击此页面上的文本区域,如顶部的搜索框。上下文菜单将隐藏,但光标不会聚焦文本框(除非您在关闭菜单时再次单击它)。

我们如何在JavaScript中模拟此行为?

我们考虑的拒绝选项

  1. 在整个页面上使用透明div。问题:这可以捕获任何地方的点击次数,但会中断悬停事件并悬停css。

  2. 在每个点击处理程序中检查上下文菜单打开变量,并为所有链接分配处理程序,并输入元素以检测上下文菜单打开状态,这将关闭上下文菜单,取消设置打开状态并防止处理程序默认。问题:非常草率的代码和维护噩梦。

2 个答案:

答案 0 :(得分:1)

考虑被拒绝的选项#2的变体,其中文档上有一个事件监听器。

document.addEventListener('click', function (e) {
    if (contextMenuOpen) {
        e.preventDefault();
        e.stopPropagation();
    }
}, true);

有关true的更多信息,请查看useCaptureevent flow

答案 1 :(得分:0)

Guest在事件捕获的正确轨道上,但解决方案有一些小问题。这是一个更强大的解决方案,可以解决以下问题:

  1. 不要立即关闭右键单击事件中的菜单,该事件会在上下文菜单后立即触发。
  2. 当上下文菜单打开时,不要让文本字段聚焦 - 焦点事件首先触发,并且不会被捕获点击事件捕获。我们还需要在焦点上设置捕获处理程序。
  3. 处理由焦点和点击处理程序创建的问题,这些问题都会触发。
  4. 为此,您需要两个捕获事件处理程序:

    document.addEventListener('focus', function(e){eDocumentFocusCapture(e)}, true);
    document.addEventListener('click', function(e){eDocumentClickCapture(e)}, true);
    
    // If the context menu is open, ignore the focus event.
    eDocumentFocusCapture = function(e){
       if(RowContextMenuIsOpen){
          console.log('focus event sees the menu open: cancel focus, but leave menu be. Click will take care of closing it.');
          e.stopImmediatePropagation();
          e.preventDefault();
          e.target.blur(); // tell the clicked element it is not focused, otherwise you can't focus it until you click elsewhere first!
       }
    }
    
    
    eDocumentClickCapture = function(e){   
    
       // A right click fires immediatly after context menu is fired,
       // we prevent the menu from closing immediately by skipping one right click event
       if(RowContextMenuWasJustOpened===true && e.button===2){
          console.log('right click self bypass');
          RowContextMenuWasJustOpened=false;
          return;
       }
    
       if(this.protected.RowContextMenuIsOpen){
          console.log('click event sees menu open, I will close it.');
          this.HideRowContextMenu();      
          e.stopImmediatePropagation();
          e.preventDefault();      
       }
    }