如何检测元素外的点击?

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

是这样的jQuery可能吗?

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

注意:使用stopEventPropagation()是应该避免的,因为它会打破DOM中的正常事件流。 有关更多信息,请参阅此文章。 考虑使用这种方法。

将单击事件附加到关闭窗口的文档主体。 将一个单独的点击事件附加到停止传播到文档主体的窗口。

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

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

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

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

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

编辑 - 2017-06-23

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

export function hideOnClickOutside(selector) {
  const outsideClickListener = (event) => {
    if (!$(event.target).closest(selector).length) {
      if ($(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)) { // or use: event.target.closest(selector) === null
            if (isVisible(element)) {
                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版本有点不同)。 Polyfills可以在这里找到:https://developer.mozilla.org/en-US/docs/Web/API/Element/closest


如何检测元素外的点击?

这个问题如此受欢迎并有如此多答案的原因是它看起来很复杂。 经过近八年的时间和几十个答案,我真的很惊讶地发现,对可访问性的关注很少。

当用户点击菜单区域外时,我想隐藏这些元素。

这是一个崇高的事业,是实际的问题。 问题的题目 - 这是大多数答案似乎试图解决的问题 - 包含一个不幸的红色鲱鱼。

提示:这是“点击”一词!

你实际上不想绑定点击处理程序。

如果你绑定了点击处理程序来关闭对话框,那么你已经失败了。 你失败的原因是不是每个人都触发click事件。 不使用鼠标的用户将能够通过按下Tab键来跳出对话框(并且弹出菜单可以说是一种对话框类型),然后他们将无法读取对话框后面的内容,而不会随后触发click事件。

所以我们来重述一下这个问题。

当用户完成对话时,如何关闭对话框?

这是目标。 不幸的是,现在我们需要绑定用户完成的userisfinishedwiththedialog事件,并且绑定并不那么直截了当。

那么我们如何检测到用户已经完成了使用对话?

focusout活动

一个好的开始是确定焦点是否已经离开对话。

提示:注意blur事件,如果事件被绑定到冒泡阶段, blur不会传播!

jQuery的focusout将会很好。 如果你不能使用jQuery,那么你可以在捕获阶段使用blur

element.addEventListener('blur', ..., true);
//                       use capture: ^^^^

另外,对于许多对话框,您需要允许容器获得焦点。 添加tabindex="-1"以允许对话框动态接收焦点,而不会中断Tab键流。

$('a').on('click', function () {
  $(this.hash).toggleClass('active').focus();
});

$('div').on('focusout', function () {
  $(this).removeClass('active');
});
div {
  display: none;
}
.active {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#example">Example</a>
<div id="example" tabindex="-1">
  Lorem ipsum <a href="http://example.com">dolor</a> sit amet.
</div>
链接地址: http://www.djcxy.com/p/271.html

上一篇: How do I detect a click outside an element?

下一篇: Is there an "exists" function for jQuery?