如何检测元素外的点击?

新手上路,请多包涵

我有一些 HTML 菜单,当用户单击这些菜单的头部时,我会完全显示这些菜单。当用户在菜单区域之外单击时,我想隐藏这些元素。

jQuery可以做到这样的事情吗?

$("#menuscontainer").clickOutsideThisElement(function() {
    // Hide the menus
});

原文由 Sergio del Amo 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.4k
2 个回答

注意:应该避免使用 stopPropagation ,因为它会破坏 DOM 中的正常事件流。有关更多信息,请参阅 这篇 CSS 技巧文章。请考虑改用 此方法

将单击事件附加到关闭窗口的文档正文。将单独的单击事件附加到容器,以停止传播到文档正文。

 $(window).click(function() {
 //Hide the menus if visible
 });

 $('#menucontainer').click(function(event){
 event.stopPropagation();
 });

原文由 Eran Galperin 发布,翻译遵循 CC BY-SA 4.0 许可协议

您可以在 document 上监听 点击 事件,然后确保 #menucontainer 不是祖先或点击元素的目标,方法是使用 .closest()

如果不是,则单击的元素在 #menucontainer 之外,您可以安全地隐藏它。

 $(document).click(function(event) {
  var $target = $(event.target);
  if(!$target.closest('#menucontainer').length &&
  $('#menucontainer').is(":visible")) {
    $('#menucontainer').hide();
  }
});

编辑 – 2017-06-23

如果您打算关闭菜单并想停止监听事件,您也可以在事件监听器之后进行清理。此函数将仅清除新创建的侦听器,保留 document 上的任何其他点击侦听器。使用 ES2015 语法:

 export function hideOnClickOutside(selector) {
  const outsideClickListener = (event) => {
    const $target = $(event.target);
    if (!$target.closest(selector).length && $(selector).is(':visible')) {
        $(selector).hide();
        removeClickListener();
    }
  }

  const removeClickListener = () => {
    document.removeEventListener('click', outsideClickListener);
  }

  document.addEventListener('click', outsideClickListener);
}

编辑 – 2018-03-11

对于那些不想使用 jQuery 的人。这是普通 vanillaJS (ECMAScript6) 中的上述代码。

 function hideOnClickOutside(element) {
    const outsideClickListener = event => {
        if (!element.contains(event.target) && isVisible(element)) { // or use: event.target.closest(selector) === null
          element.style.display = 'none';
          removeClickListener();
        }
    }

    const removeClickListener = () => {
        document.removeEventListener('click', outsideClickListener);
    }

    document.addEventListener('click', outsideClickListener);
}

const isVisible = elem => !!elem && !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); // source (2018-03-11): https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js

注意: 这是基于 Alex 的评论,只使用 !element.contains(event.target) 而不是 jQuery 部分。

但是 element.closest() 现在也可以在所有主要浏览器中使用(W3C 版本与 jQuery 版本略有不同)。可以在这里找到 Polyfill: Element.closest()

编辑 – 2020-05-21

如果您希望用户能够在元素内单击并拖动,然后在元素外释放鼠标,而不关闭元素:

       ...
      let lastMouseDownX = 0;
      let lastMouseDownY = 0;
      let lastMouseDownWasOutside = false;

      const mouseDownListener = (event: MouseEvent) => {
        lastMouseDownX = event.offsetX;
        lastMouseDownY = event.offsetY;
        lastMouseDownWasOutside = !$(event.target).closest(element).length;
      }
      document.addEventListener('mousedown', mouseDownListener);

outsideClickListener 中:

 const outsideClickListener = event => {
        const deltaX = event.offsetX - lastMouseDownX;
        const deltaY = event.offsetY - lastMouseDownY;
        const distSq = (deltaX * deltaX) + (deltaY * deltaY);
        const isDrag = distSq > 3;
        const isDragException = isDrag && !lastMouseDownWasOutside;

        if (!element.contains(event.target) && isVisible(element) && !isDragException) { // or use: event.target.closest(selector) === null
          element.style.display = 'none';
          removeClickListener();
          document.removeEventListener('mousedown', mouseDownListener); // Or add this line to removeClickListener()
        }
    }

原文由 Art 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题