如何从页面上的任何地方(其他地方)点击关闭 Bootstrap 弹出窗口?

我现在使用的是 Bootstrap 泡芙,初始状态是这样的:

$('.popup-marker').popover({
html: true,
trigger: 'manual'
}).click(function(e) {
$(this).popover('toggle');
e.preventDefault();
});

如您所见,它们是手动触发的,并点击。Popup-mark (是一个带有背景图像的 div)切换一个 popover。这个工作非常好,但是我也希望能够在页面的任何其他地方点击关闭弹出窗口(但不是在弹出窗口本身!).

我尝试了一些不同的方法,包括以下方法,但是没有结果:

$('body').click(function(e) {
$('.popup-marker').popover('hide');
});

我如何关闭弹出窗口与点击页面上的任何其他地方,但不点击弹出窗口本身?

162835 次浏览

假设在任何时候只能看到一个 popover,那么您可以使用一组标志来标记什么时候可以看到 popover,然后再隐藏它们。

如果您在文档主体上设置了事件侦听器,当您单击标记为“ popup-mark”的元素时,它将触发。因此,您必须对事件对象调用 stopPropagation()。并且在点击泡芙本身的时候应用同样的技巧。

下面是一个实现这个功能的 JavaScript 代码,它使用 jQuery > = 1.7

jQuery(function() {
var isVisible = false;


var hideAllPopovers = function() {
$('.popup-marker').each(function() {
$(this).popover('hide');
});
};


$('.popup-marker').popover({
html: true,
trigger: 'manual'
}).on('click', function(e) {
// if any other popovers are visible, hide them
if(isVisible) {
hideAllPopovers();
}


$(this).popover('show');


// handle clicking on the popover itself
$('.popover').off('click').on('click', function(e) {
e.stopPropagation(); // prevent event for bubbling up => will not get caught with document.onclick
});


isVisible = true;
e.stopPropagation();
});




$(document).on('click', function(e) {
hideAllPopovers();
isVisible = false;
});
});

Http://jsfiddle.net/afffl/539/

唯一的警告是你不能同时打开2个泡芙。但我认为这会让用户感到困惑: -)

jQuery(':not(.popup-marker)').once().click(function(){
jQuery('.popup-marker').hide();
});

我也有类似的需求,找到了这个 李 · 卡迈克尔(Lee Carmichael)的 Bootstrap Popover 的一个很棒的小扩展,名为 bootstrapX-clickover。他还有一些用法例子 给你。基本上,它将改变弹出窗口成为一个交互式组件,将关闭时,您点击页面上的其他地方,或在关闭按钮内弹出窗口。这也将允许一次打开多个弹出窗口和其他一些不错的功能。

插件可以在这里找到。

用法例子

<button rel="clickover" data-content="Show something here.
<button data-dismiss='clickover'
>Close Clickover</button>"
>Show clickover</button>

Javascript:

// load click overs using 'rel' attribute
$('[rel="clickover"]').clickover();

这就更简单了:

$('html').click(function(e) {
$('.popup-marker').popover('hide');
});


$('.popup-marker').popover({
html: true,
trigger: 'manual'
}).click(function(e) {
$(this).popover('toggle');
e.stopPropagation();
});

我是这样做的

$("a[rel=popover]").click(function(event){
if(event.which == 1)
{
$thisPopOver = $(this);
$thisPopOver.popover('toggle');
$thisPopOver.parent("li").click(function(event){
event.stopPropagation();
$("html").click(function(){
$thisPopOver.popover('hide');
});
});
}
});

希望这个能帮上忙!

Https://github.com/lecar-red/bootstrapx-clickover

这是 Bootstrap 泡芙的一种延伸,将非常简单地解决这个问题。

下面是一个对我非常有效的解决方案,如果它有帮助的话:

/**
* Add the equals method to the jquery objects
*/
$.fn.equals = function(compareTo) {
if (!compareTo || this.length !== compareTo.length) {
return false;
}
for (var i = 0; i < this.length; ++i) {
if (this[i] !== compareTo[i]) {
return false;
}
}
return true;
};


/**
* Activate popover message for all concerned fields
*/
var popoverOpened = null;
$(function() {
$('span.btn').popover();
$('span.btn').unbind("click");
$('span.btn').bind("click", function(e) {
e.stopPropagation();
if($(this).equals(popoverOpened)) return;
if(popoverOpened !== null) {
popoverOpened.popover("hide");
}
$(this).popover('show');
popoverOpened = $(this);
e.preventDefault();
});


$(document).click(function(e) {
if(popoverOpened !== null) {
popoverOpened.popover("hide");
popoverOpened = null;
}
});
});

出于某种原因,这里的其他解决方案都不适合我。然而,经过大量的故障排除,我终于找到了这个完美工作的方法(至少对我来说)。

$('html').click(function(e) {
if( !$(e.target).parents().hasClass('popover') ) {
$('#popover_parent').popover('destroy');
}
});

在我的例子中,我将一个弹出窗口添加到一个表中,并将其绝对定位在被点击的 td的上方或下方。表选择是由 jQuery-UI Selectable 处理的,所以我不确定这是否会造成干扰。然而,每当我点击弹出窗口内我的点击处理程序的目标 $('.popover')从来没有工作,事件处理总是委派给 $(html)点击处理程序。我对 JS 还不太熟悉所以也许我漏掉了什么?

不管怎样,我希望这对某人有帮助!

试试 data-trigger="focus"而不是 "click"

这为我解决了问题。

如果你想在 pjax 中使用 Bootstrap 泡芙,这个方法对我很有效:

App.Utils.Popover = {


enableAll: function() {
$('.pk-popover').popover(
{
trigger: 'click',
html : true,
container: 'body',
placement: 'right',
}
);
},


bindDocumentClickEvent: function(documentObj) {
$(documentObj).click(function(event) {
if( !$(event.target).hasClass('pk-popover') ) {
$('.pk-popover').popover('hide');
}
});
}


};


$(document).on('ready pjax:end', function() {
App.Utils.Popover.enableAll();
App.Utils.Popover.bindDocumentClickEvent(this);
});

我给我所有的泡芙锚类 activate_popover。我激活他们所有一次上载

$('body').popover({selector: '.activate-popover', html : true, container: 'body'})

为了使我使用的点击功能正常工作(在咖啡脚本中) :

$(document).on('click', (e) ->
clickedOnActivate = ($(e.target).parents().hasClass("activate-popover") || $(e.target).hasClass("activate-popover"))
clickedAway = !($(e.target).parents().hasClass("popover") || $(e.target).hasClass("popover"))
if clickedAway && !clickedOnActivate
$(".popover.in").prev().popover('hide')
if clickedOnActivate
$(".popover.in").prev().each () ->
if !$(this).is($(e.target).closest('.activate-popover'))
$(this).popover('hide')
)

它在 bootstrap 2.3.1中运行得非常好

接受的解决方案给了我一些问题(点击’。弹出标记的元素打开的泡芙,使泡芙不工作后)。我想出了另一个完美的解决方案,它非常简单(我使用 Bootstrap 2.3.1) :

$('.popup-marker').popover({
html: true,
trigger: 'manual'
}).click(function(e) {
$('.popup-marker').not(this).popover('hide');
$(this).popover('toggle');
});
$(document).click(function(e) {
if (!$(e.target).is('.popup-marker, .popover-title, .popover-content')) {
$('.popup-marker').popover('hide');
}
});

更新: 这段代码同样适用于 Bootstrap 3!

@ RayOnAir 我对以前的解决方案也有同样的问题。我也很接近“ RayOnAir 解决方案”。一件改进的事情是关闭已经打开的弹出窗口,当点击其他弹出窗口标记。所以我的代码是:

var clicked_popover_marker = null;
var popover_marker = '#pricing i';


$(popover_marker).popover({
html: true,
trigger: 'manual'
}).click(function (e) {
clicked_popover_marker = this;


$(popover_marker).not(clicked_popover_marker).popover('hide');
$(clicked_popover_marker).popover('toggle');
});


$(document).click(function (e) {
if (e.target != clicked_popover_marker) {
$(popover_marker).popover('hide');
clicked_popover_marker = null;
}
});

不管怎样,我的解决办法是:

// Listen for clicks or touches on the page
$("html").on("click.popover.data-api touchend.popover.data-api", function(e) {


// Loop through each popover on the page
$("[data-toggle=popover]").each(function() {


// Hide this popover if it's visible and if the user clicked outside of it
if ($(this).next('div.popover:visible').length && $(".popover").has(e.target).length === 0) {
$(this).popover("hide");
}


});
});

我发现这是 pbaron 上面建议的一个修改过的解决方案,因为他的解决方案激活了所有具有“ popup-mark”类的元素上的 popover (“隐藏”)。然而,当您使用 popover ()来代替数据内容来处理 html 内容时,正如我在下面所做的那样,在 html 弹出窗口中的任何点击实际上都会激活 popover (‘ hide’) ,它会立即关闭窗口。下面的方法迭代每个。弹出标记元素,并首先发现父元素是否与。弹出式标记的 id 被点击,如果是这样,那么不隐藏它。其他的都被藏起来了。

        $(function(){
$('html').click(function(e) {
// this is my departure from pbaron's code above
// $('.popup-marker').popover('hide');
$('.popup-marker').each(function() {
if ($(e.target).parents().children('.popup-marker').attr('id')!=($(this).attr('id'))) {
$(this).popover('hide');
}
});
});


$('.popup-marker').popover({
html: true,
// this is where I'm setting the html for content from a nearby hidden div with id="html-"+clicked_div_id
content: function() { return $('#html-'+$(this).attr('id')).html(); },
trigger: 'manual'
}).click(function(e) {
$(this).popover('toggle');
e.stopPropagation();
});
});

我想到了这个:

我的场景在同一个页面上包含了更多的泡芙,隐藏它们只会让它们变得不可见,正因为如此,点击泡芙背后的项目是不可能的。 这个想法是将特定的 popover-link 标记为“活动”,然后您可以简单地“切换”活动 popover。这样做将完全关闭酥皮。

$('.popover-link').popover({ html : true, container: 'body' })


$('.popover-link').popover().on 'shown.bs.popover', ->
$(this).addClass('toggled')


$('.popover-link').popover().on 'hidden.bs.popover', ->
$(this).removeClass('toggled')


$("body").on "click", (e) ->
$openedPopoverLink = $(".popover-link.toggled")
if $openedPopoverLink.has(e.target).length == 0
$openedPopoverLink.popover "toggle"
$openedPopoverLink.removeClass "toggled"

尽管这里有很多解决方案,我也想提出我的,我不知道是否有一些解决方案可以解决所有问题,但是我尝试了其中的3个,他们有问题,比如点击弹出窗口本身使其隐藏,其他的如果我有另一个弹出窗口按钮点击两个/多个弹出窗口仍然会出现(像在选定的解决方案) ,怎么办,这个人把一切都搞定了

var curr_popover_btn = null;
// Hide popovers function
function hide_popovers(e)
{
var container = $(".popover.in");
if (!container.is(e.target) // if the target of the click isn't the container...
&& container.has(e.target).length === 0) // ... nor a descendant of the container
{
if( curr_popover_btn != null )
{
$(curr_popover_btn).popover('hide');
curr_popover_btn = null;
}
container.hide();
}
}
// Hide popovers when out of focus
$('html').click(function(e) {
hide_popovers(e);
});
$('.popover-marker').popover({
trigger: 'manual'
}).click(function(e) {
hide_popovers(e);
var $popover_btns = $('.popover-marker');
curr_popover_btn = this;
var $other_popover_btns = jQuery.grep($($popover_btns), function(popover_btn){
return ( popover_btn !== curr_popover_btn );
});
$($other_popover_btns).popover('hide');
$(this).popover('toggle');
e.stopPropagation();
});

所有现有的答案都相当薄弱,因为它们依赖于捕获 所有文档事件,然后寻找活跃的 popover,或者修改对 .popover()的调用。

更好的方法是监听文档主体上的 show.bs.popover事件,然后作出相应的反应。下面的代码在单击文档或按下 esc时关闭弹出窗口,在显示弹出窗口时关闭 只有绑定事件侦听器:

function closePopoversOnDocumentEvents() {
var visiblePopovers = [];


var $body = $("body");


function hideVisiblePopovers() {
$.each(visiblePopovers, function() {
$(this).popover("hide");
});
}


function onBodyClick(event) {
if (event.isDefaultPrevented())
return;


var $target = $(event.target);
if ($target.data("bs.popover"))
return;


if ($target.parents(".popover").length)
return;


hideVisiblePopovers();
}


function onBodyKeyup(event) {
if (event.isDefaultPrevented())
return;


if (event.keyCode != 27) // esc
return;


hideVisiblePopovers();
event.preventDefault();
}


function onPopoverShow(event) {
if (!visiblePopovers.length) {
$body.on("click", onBodyClick);
$body.on("keyup", onBodyKeyup);
}
visiblePopovers.push(event.target);
}


function onPopoverHide(event) {
var target = event.target;
var index = visiblePopovers.indexOf(target);
if (index > -1) {
visiblePopovers.splice(index, 1);
}
if (visiblePopovers.length == 0) {
$body.off("click", onBodyClick);
$body.off("keyup", onBodyKeyup);
}
}


$body.on("show.bs.popover", onPopoverShow);
$body.on("hide.bs.popover", onPopoverHide);
}

在 bootstrap 2.3.2中我遇到了一些问题。 但我喜欢这样:

$(function () {
$(document).mouseup(function (e) {
if(($('.popover').length > 0) && !$(e.target).hasClass('popInfo')) {
$('.popover').each(function(){
$(this).prev('.popInfo').popover('hide');
});
}
});


$('.popInfo').popover({
trigger: 'click',
html: true
});
});

略微调整了@David Woever 的解决方案:

function closePopoversOnDocumentEvents() {
var visiblePopovers = [];


var $body = $("body");


function hideVisiblePopovers() {
/* this was giving problems and had a bit of overhead
$.each(visiblePopovers, function() {
$(this).popover("hide");
});
*/
while (visiblePopovers.length !== 0) {
$(visiblePopovers.pop()).popover("hide");
}
}


function onBodyClick(event) {
if (event.isDefaultPrevented())
return;


var $target = $(event.target);
if ($target.data("bs.popover"))
return;


if ($target.parents(".popover").length)
return;


hideVisiblePopovers();
}


function onBodyKeyup(event) {
if (event.isDefaultPrevented())
return;


if (event.keyCode != 27) // esc
return;


hideVisiblePopovers();
event.preventDefault();
}


function onPopoverShow(event) {
if (!visiblePopovers.length) {
$body.on("click", onBodyClick);
$body.on("keyup", onBodyKeyup);
}
visiblePopovers.push(event.target);
}


function onPopoverHide(event) {
var target = event.target;
var index = visiblePopovers.indexOf(target);
if (index > -1) {
visiblePopovers.splice(index, 1);
}
if (visiblePopovers.length == 0) {
$body.off("click", onBodyClick);
$body.off("keyup", onBodyKeyup);
}
}


$body.on("show.bs.popover", onPopoverShow);
$body.on("hide.bs.popover", onPopoverHide);
}

这里也有人提出了这个问题,我的答案不仅提供了一种理解 jQuery DOM 遍历方法的方法,而且提供了两个通过单击外部来处理弹出窗口关闭的选项。

一次打开多个泡芙或一次打开一个泡芙。

另外,这些小代码片段可以处理包含图标的按钮的关闭!

Https://stackoverflow.com/a/14857326/1060487

这个很管用,我会好好利用。

当你点击时它会打开弹出窗口,如果你再次点击它将关闭,也如果你点击外面的弹出窗口将关闭。

这也适用于一个以上的泡芙。

    function hideAllPopovers(){
$('[data-toggle="popover"]').each(function() {
if ($(this).data("showing") == "true"){
$(this).data("showing", "false");
$(this).popover('hide');
}
});
}
$('[data-toggle="popover"]').each(function() {
$(this).popover({
html: true,
trigger: 'manual'
}).click(function(e) {
if ($(this).data("showing") !=  "true"){
hideAllPopovers();
$(this).data("showing", "true");
$(this).popover('show');
}else{
hideAllPopovers();
}
e.stopPropagation();
});
});


$(document).click(function(e) {
hideAllPopovers();
});

读“下次点击解散” 这里有一个 href = “ http://getbootstrap.com/javascript/# popover”> http://getbootstrap.com/javascript/#popovers

您可以使用焦点触发器在下一次单击时解除弹出窗口,但是您必须使用 <a>标记,而不是 <button>标记,并且您还必须包含一个 tabindex属性..。

例如:

<a href="#" tabindex="0" class="btn btn-lg btn-danger"
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>

我只是想为一个简单的问题找到一个简单的解决方案。上面的帖子很好,但是对于一个简单的问题来说太复杂了。所以我做了个简单的决定。只是加了个关闭按钮。对我来说太完美了。

            $(".popover-link").click(function(){
$(".mypopover").hide();
$(this).parent().find(".mypopover").show();
})
$('.close').click(function(){
$(this).parents('.mypopover').css('display','none');
});






<div class="popover-content">
<i class="fa fa-times close"></i>
<h3 class="popover-title">Title here</h3>
your other content here
</div>




.popover-content {
position:relative;
}
.close {
position:absolute;
color:#CCC;
right:5px;
top:5px;
cursor:pointer;
}

我喜欢这个,简单而有效. 。

var openPopup;


$('[data-toggle="popover"]').on('click',function(){
if(openPopup){
$(openPopup).popover('hide');


}
openPopup=this;
});

我会将焦点设置为新创建的弹出窗口,并删除它的模糊。这样就不需要检查 DOM 的哪个元素被点击了,弹出窗口也可以被点击和选择: 它不会失去焦点,也不会消失。

密码:

    $('.popup-marker').popover({
html: true,
trigger: 'manual'
}).click(function(e) {
$(this).popover('toggle');
// set the focus on the popover itself
jQuery(".popover").attr("tabindex",-1).focus();
e.preventDefault();
});


// live event, will delete the popover by clicking any part of the page
$('body').on('blur','.popover',function(){
$('.popup-marker').popover('hide');
});

btn-popover类添加到弹出窗口按钮/链接,以打开弹出窗口。这段代码将关闭弹出窗口,当点击它的外面。

$('body').on('click', function(event) {
if (!$(event.target).closest('.btn-popover, .popover').length) {
$('.popover').popover('hide');
}
});

一个更简单的解决方案,只需迭代通过所有泡芙和隐藏,如果没有 this

$(document).on('click', '.popup-marker', function() {
$(this).popover('toggle')
})


$(document).bind('click touchstart', function(e) {
var target = $(e.target)[0];
$('.popup-marker').each(function () {
// hide any open popovers except for the one we've clicked
if (!$(this).is(target)) {
$(this).popover('hide');
}
});
});
$('.popForm').popover();


$('.conteneurPopForm').on("click",".fermePopover",function(){
$(".popForm").trigger("click");
});

先说清楚,只要触发酥饼就行了

另一个解决方案是,它解决了我在点击泡芙后代时遇到的问题:

$(document).mouseup(function (e) {
// The target is not popover or popover descendants
if (!$(".popover").is(e.target) && 0 === $(".popover").has(e.target).length) {
$("[data-toggle=popover]").popover('hide');
}
});

这个应该可以在 Bootstrap 4中使用:

$("#my-popover-trigger").popover({
template: '<div class="popover my-popover-content" role="tooltip"><div class="arrow"></div><div class="popover-body"></div></div>',
trigger: "manual"
})


$(document).click(function(e) {
if ($(e.target).closest($("#my-popover-trigger")).length > 0) {
$("#my-popover-trigger").popover("toggle")
} else if (!$(e.target).closest($(".my-popover-content")).length > 0) {
$("#my-popover-trigger").popover("hide")
}
})

说明:

  • 第一部分根据文档初始化 popover: https://getbootstrap.com/docs/4.0/components/popovers/
  • 第二部分中的第一个“ if”检查单击的元素是否是 # my-popover-touch 的后代。如果这是真的,它切换弹出窗口(它处理触发器上的点击)。
  • 第二部分中的第二个“ if”检查单击的元素是否是在 init 模板中定义的 popover 内容类的后代。如果不是,这意味着点击不在弹出窗口内容内,并且弹出窗口可以被隐藏。