Bootstrap弹出框,点击外部隐藏?

28
使用Bootstrap Popover,现在我正在尝试使代码在单击弹出框外部时关闭弹出框:
$('body').on('click', function (e) {
    $('[data-toggle="popover"]').each(function () {
        //the 'is' for buttons that trigger popups
        //the 'has' for icons within a button that triggers a popup
        if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
            $(this).popover('hide');
        }
    });
});

但是当我使用这部分代码时,虽然可以关闭弹出窗口,但是我无法点击其他按钮,有没有人知道如何解决?
所有的按钮:
<a href="#" class="btn btn-xs btn-primary" data-toggle="popover">This opens popover</a>
<a href="#" class="btn btn-xs btn-primary">Other link</a> <- Doesn't work 
<a href="#" class="btn btn-xs btn-primary">Other link</a> <- Doesn't work 

最好检查一下你的 z-index,我觉得有些东西覆盖了弹出框。 - Rahil Wazir
@RahilWazir 那有点帮助,弹出框有类.fade和淡入淡出效果,.fade的不透明度为0,所以它仍然存在但是看不见^^现在我需要找出如何从中去除不透明度,因为当我这样做时,我用于关闭它的代码将无法工作。 - Tommy
创建一个 Fiddle,这会很有帮助。 - Rahil Wazir
你说的“不工作”是什么意思?能否在jsfiddle上提供一个演示? - Irvin Dominin
10个回答

49

我发现了这个:http://bootply.com/99372

$('body').on('click', function (e) {
    $('[data-toggle=popover]').each(function () {
        // hide any open popovers when the anywhere else in the body is clicked
        if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
            $(this).popover('hide');
        }
    });
});

这段代码与您之前的代码几乎相同...


问题在于,由于某种原因,手动调用popover('hide')无法将其从dom中移除,因此popover div仍然存在并覆盖在其下方的任何内容。 - Erick Smith
你能解释一下你的问题或者创建一个fiddle吗? - BENARD Patrick
Bootstrap发布了一个修复我的问题的版本,所以你的解决方案现在可以按照你描述的方式工作。在此之前,弹出框会保留在DOM中。它可能是不可见的,但仍然保持其HxW大小,从而使其下面的任何元素的z-index无法被点击。 - Erick Smith
对于工具提示也适用,只需将所有的“popover”字符串更改为“tooltip”。 - simPod
3
我建议使用“mousedown”事件而不是“click”事件。这样,当进行长时间选择或拖放操作时,弹出框也将被隐藏。 - Stepan Stepanov
这很棒,因为它在打开另一个弹出窗口之前会关闭任何已打开的弹出窗口。同时打开多个弹出窗口是很烦人的,而且打开的弹出窗口越多,它们遮挡住你需要点击关闭的元素的机会就越大。由于没有关闭按钮,这应该是默认行为。它还可以帮助那些慌张的用户,他们只是开始到处点击以关闭这个突兀、不直观的弹出窗口。 - undefined

14

只需添加此元素以在下一次单击时关闭浮动提示。

data-trigger="focus" 

参考自此处:Bootstrap 弹出框


有人可以解释一下为什么这个答案被踩了吗?在我看来,它是完美的答案。它既简短、具体、正确,而且还引用了官方文档。我不明白。 - jumps4fun
2
我不是那个给它点踩的人,但原因可能是它并不是那个人所问的。他(和我)希望当在弹出框外部点击时才会消失。而 data-trigger="focus" 会在内部点击时也隐藏它。 - Asaf
1
@Asaf 不是这样的... 我想要在内部和外部点击时都关闭,但只有在我点击外部时才起作用.. 我该如何实现两者。所谓的内部,是指点击 ICON 会导致弹出气泡。是的,当我在气泡体内点击时它确实消失了。 - Anshul Riyal

8
事实上,您甚至不需要 JavaScript,因为在 Bootstrap 中已经有一个设置可以实现此功能。 请参考:http://getbootstrap.com/javascript/#dismiss-on-next-click "按下一个按钮后关闭的特定标记要求。为了实现正确的跨浏览器和跨平台行为,您必须使用 <a> 标记而不是 <button> 标记,并且还必须包括 role="button" 和 tabindex 属性。" 例如:
<a tabindex="0" class="btn btn-lg btn-danger" role="button" data-toggle="popover" data-trigger="focus" title="Dismissible popover" data-content="And here's some amazing content. It's very engaging. Right?">Dismissible popover</a>

1
如果您包含外部资源中相关的(代码)部分,而不仅仅是链接到它,那么这总是很有帮助的。 - Ted Nyberg
8
虽然这不是最完整的答案,但这是正确的操作方式。但是,如果您选择在其中放置任何交互内容,这将无法正常工作,因为所有点击都会关闭弹出窗口。 - Phil Andrews
谢谢,你的解决方案有效。Bootstrap为此提供了默认设置。 - Gautam Patadiya
3
第二次点击将关闭弹出窗口,而不是在外部点击时关闭。 即使我在弹出窗口内单击,它也会关闭。 - Lombas
谢谢,这是我正在寻找的正确方式。 - Taufik Nur Rahmanda
显示剩余2条评论

6
尝试这个。当点击弹出框之外时,它将关闭弹出框。
$('body').on('click', function (e) {
//did not click a popover toggle, or icon in popover toggle, or popover
if ($(e.target).data('toggle') !== 'popover' && $(e.target).parents('[data-toggle="popover"]').length === 0
    && $(e.target).parents('.popover.in').length === 0) {
    (($('[data-toggle="popover"]').popover('hide').data('bs.popover') || {}).inState || {}).click = false;
}
});

另一个解决方案是,

<a tabindex="0" class="btn btn-lg btn-danger" role="button" data-toggle="popover" data-trigger="focus" title="Dismissible popover" data-content="And here's some amazing content. It's very engaging. Right?">Dismissible popover</a>

添加 tabindex="0"data-trigger="focus"


4
隐藏气泡提示框并不能起作用。您需要点击两次才能再次显示气泡提示框。 https://github.com/twbs/bootstrap/issues/16732 为了在Bootstrap 3.3.6中正确使用,请尝试以下操作:
$('body').on('click', function (e) {
        $('[data-toggle=popover]').each(function () {
            if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
                (($(this).popover('hide').data('bs.popover')||{}).inState||{}).click = false;
            }
        });
    });

Bootstrap 4使用_activeTrigger代替inState

$(e.target).data("bs.popover")._activeTrigger.click = false

这里的'inState'是什么? - Vivekraj K R
2
inState 表示弹出窗口的当前状态。 在这里,我们使用 'inState.click=false' 重置了弹出窗口的单击状态, 否则它将是 'true',因为我们使用单击事件来显示此弹出窗口。 'inState.hover' 和 'inState.focus' 是一些可用选项。 - SumitK
如果您觉得这个信息有用,请点赞。Vivekraj K R - SumitK

2

我刚刚编写了自己版本的你的答案,因为我遇到了一个问题:如果我尝试在外部单击后重新打开弹出窗口,我需要点击两次按钮。

这段代码的目标是模拟单击激活弹出窗口的按钮。

所以这就是代码:

$('html').on('click', function(e) {
    $('[data-toggle="popover"]').each(function() { //Loop for everything containing a data-toggle="popover"
        if ($(this).attr('aria-describedby') != null ) { //Check if the popover is active / contain an aria-describedby with a value
            var id = $(this).attr('aria-describedby'); //Put the value in a variable
            if (!$(e.target).closest(".popover-content").length && $(e.target).attr("aria-describedby") != id && !$(e.target).closest('[aria-describedby="'+id+'"').length) { //Look if the click is a child of the popover box or if it's the button itself or a child of the button
                $('[aria-describedby="'+id+'"]').trigger( "click" ); //trigger a click as if you clicked the button
            }
        }
    });
});

这个解决方案几乎在任何时候都可以工作。我认为stoppropagation无法阻止它。问题是,每次点击时,此函数将循环处理每个弹出窗口。其他解决方案可能更好,例如内置的解决方案。在某些情况下,您可能会遇到问题,因此此代码将完成工作。 - Elie Morin

1

我曾经也遇到过这个问题,但是后来找到了解决办法。

只需要在你的代码中添加以下这行:

 $(this).css('display', 'none');

i.e

    $('[data-toggle="popover"]').each(function () {
        //the 'is' for buttons that trigger popups
        //the 'has' for icons within a button that triggers a popup
        if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
            $(this).popover('hide');
          $('[data-toggle="popover"]').css('display','none');
        }
    });
});

建议: 不要使用 'body' 标签,而是使用 'document'

这样可以更好地操作文档。


0

实际上,我对这段代码感到满意,因为以上的解决方案都没有对我起作用:

 $('body').on('mouseleave', '.popover', function () {
        $(this).hide();
    });

是的,它可以工作。但是当您尝试再次点击弹出窗口时,它将无法工作。 - Joseph Miller

0

Bootstrap无法独立访问弹出窗口的id。我们需要读取与元素相关的aria-describedby属性。

以下代码将删除弹出窗口:

$("#"+$(relatedElementId).attr("aria-describedby")).remove();

相关元素ID:弹出窗口关联的元素。

0
**Try this**,below code is work for me,
Put below code in js file

$(function () {
    $('[data-toggle="popover"]').popover();
});
$('html').on('click', function (e) {
    $('[data-toggle="popover"]').each(function () {
           if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
            $(this).popover('hide');
        }
    });
});

and HTML tag should be like this

<a data-toggle="popover"   data-placement="bottom" data-content-id="notifications-content">

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接