我有一些HTML菜单,当用户单击这些菜单的头部时,我会完全显示这些菜单。当用户在菜单区域外单击时,我希望隐藏这些元素。
jQuery是否可以实现这样的功能?
$("#menuscontainer").clickOutsideThisElement(function() {
// Hide the menus
});
我有一些HTML菜单,当用户单击这些菜单的头部时,我会完全显示这些菜单。当用户在菜单区域外单击时,我希望隐藏这些元素。
jQuery是否可以实现这样的功能?
$("#menuscontainer").clickOutsideThisElement(function() {
// Hide the menus
});
当前回答
老实说,我不喜欢以前的任何解决方案。
要做到这一点,最好的方法是将“点击”事件绑定到文档,并比较该点击是否真的在元素之外(就像Art在建议中所说的那样)。
然而,您会遇到一些问题:您永远无法解除绑定,并且无法使用外部按钮打开/关闭该元素。
这就是为什么我编写了这个小插件(点击此处链接),以简化这些任务。能简单一点吗?
<a id='theButton' href="#">Toggle the menu</a><br/>
<div id='theMenu'>
I should be toggled when the above menu is clicked,
and hidden when user clicks outside.
</div>
<script>
$('#theButton').click(function(){
$('#theMenu').slideDown();
});
$("#theMenu").dClickOutside({ ignoreList: $("#theButton") }, function(clickedObj){
$(this).slideUp();
});
</script>
其他回答
首先,您必须使用mouseenter和mouseleave事件跟踪鼠标是在元素1内部还是外部。然后,您可以创建一个覆盖整个屏幕的element2来检测任何点击,并根据您是在element1内部还是外部做出相应的反应。
我强烈建议同时处理初始化和清理,出于明显的原因,element2应尽可能临时。
在下面的示例中,覆盖是位于某个位置的元素,可以通过单击内部来选择,也可以通过单击外部来取消选择。_init和_release方法是自动初始化/清理过程的一部分。该类继承自具有内部和外部元素的ClickOverlay,不用担心。我使用了outerElement.parentNode.appendChild来避免冲突。
import ClickOverlay from './ClickOverlay.js'
/* CSS */
// .unselect-helper {
// position: fixed; left: -100vw; top: -100vh;
// width: 200vw; height: 200vh;
// }
// .selected {outline: 1px solid black}
export default class ResizeOverlay extends ClickOverlay {
_init(_opts) {
this.enterListener = () => this.onEnter()
this.innerElement.addEventListener('mouseenter', this.enterListener)
this.leaveListener = () => this.onLeave()
this.innerElement.addEventListener('mouseleave', this.leaveListener)
this.selectListener = () => {
if (this.unselectHelper)
return
this.unselectHelper = document.createElement('div')
this.unselectHelper.classList.add('unselect-helper')
this.unselectListener = () => {
if (this.mouseInside)
return
this.clearUnselectHelper()
this.onUnselect()
}
this.unselectHelper.addEventListener('pointerdown'
, this.unselectListener)
this.outerElement.parentNode.appendChild(this.unselectHelper)
this.onSelect()
}
this.innerElement.addEventListener('pointerup', this.selectListener)
}
_release() {
this.innerElement.removeEventListener('mouseenter', this.enterListener)
this.innerElement.removeEventListener('mouseleave', this.leaveListener)
this.innerElement.removeEventListener('pointerup', this.selectListener)
this.clearUnselectHelper()
}
clearUnselectHelper() {
if (!this.unselectHelper)
return
this.unselectHelper.removeEventListener('pointerdown'
, this.unselectListener)
this.unselectHelper.remove()
delete this.unselectListener
delete this.unselectHelper
}
onEnter() {
this.mouseInside = true
}
onLeave() {
delete this.mouseInside
}
onSelect() {
this.innerElement.classList.add('selected')
}
onUnselect() {
this.innerElement.classList.remove('selected')
}
}
使用本机JS API最接近方法的2020解决方案。
document.addEventListener('click',({target})=>{if(!target.lestest('#menupop')){document.querySelector('#menupop').style.display=“无”}})#菜单弹出窗口{宽度:300px;高度:300px;背景色:红色;}<div id=“menupop”>单击外部将关闭此</div>
经过研究,我找到了三种可行的解决方案
第一种解决方案
<script>
//The good thing about this solution is it doesn't stop event propagation.
var clickFlag = 0;
$('body').on('click', function () {
if(clickFlag == 0) {
console.log('hide element here');
/* Hide element here */
}
else {
clickFlag=0;
}
});
$('body').on('click','#testDiv', function (event) {
clickFlag = 1;
console.log('showed the element');
/* Show the element */
});
</script>
第二种解决方案
<script>
$('body').on('click', function(e) {
if($(e.target).closest('#testDiv').length == 0) {
/* Hide dropdown here */
}
});
</script>
第三种解决方案
<script>
var specifiedElement = document.getElementById('testDiv');
document.addEventListener('click', function(event) {
var isClickInside = specifiedElement.contains(event.target);
if (isClickInside) {
console.log('You clicked inside')
}
else {
console.log('You clicked outside')
}
});
</script>
我读过2021的所有内容,但若并没有错的话,也并没有人提出过这样简单的建议,来解除和删除事件。使用了前面的两个答案和更多的小技巧,所以我把所有的都放在了一个里面(它也可以作为一个参数添加到函数中以传递选择器,以获得更多的弹出窗口)。
也许有人知道这个笑话是有用的。也可以这样做:
<div id="container" style="display:none"><h1>my menu is nice, but it disappears if I click outside it</h1></div>
<script>
function printPopup() {
$("#container").css({"display": "block"});
var remListener = $(document).mouseup(function (e) {
if ($(e.target).closest("#container").length === 0 &&
(e.target != $('html').get(0)))
{
//alert('closest call');
$("#container").css({"display": "none"});
remListener.unbind('mouseup'); // Isn't it?
}
});
}
printPopup();
</script>
使用可访问性焦点
这里有一个答案说(非常正确),关注点击事件是一个可访问性问题,因为我们想迎合键盘用户。在这里使用focusout事件是正确的,但它可以比其他答案(以及纯JavaScript)简单得多:
更简单的方法是:
使用focusout的“问题”是,如果对话框/模式/菜单中的某个元素由于“内部”的原因而失去焦点,则事件仍然会被激发。我们可以通过查看event.relatedTarget(它告诉我们哪个元素将获得焦点)来检查情况是否并非如此。
dialog = document.getElementById("dialogElement")
dialog.addEventListener("focusout", function (event) {
if (
// We are still inside the dialog so don't close
dialog.contains(event.relatedTarget) ||
// We have switched to another tab so probably don't want to close
!document.hasFocus()
) {
return;
}
dialog.close(); // Or whatever logic you want to use to close
});
上面有一个小错误,那就是relatedTarget可能为空。如果用户在对话框外单击,这很好,但如果用户在对话内单击,而对话框恰好不可聚焦,则会出现问题。要解决此问题,必须确保将tabIndex设置为0,以便对话框可聚焦。