首页 文章

如何通过页面上任何地方(否则)点击关闭Twitter Bootstrap popover?

提问于
浏览
151

我目前正在使用Twitter Bootstrap的popovers,就像这样:

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

如您所见,它们是手动触发的,然后单击.popup-marker(带有背景图像的div)切换弹出窗口 . 这很好用,但我也希望能够通过点击页面上任何其他位置来关闭popover(但不能在popover本身!) .

我尝试了一些不同的东西,包括以下内容,但没有显示结果:

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

How can I close the popover with a click anywhere else on the page, but not with a click onthe popover itself?

30 回答

  • 1

    假设在任何时候只能看到一个弹出窗口,您可以使用一组标记来标记弹出窗口何时可见,然后才隐藏它们 .

    如果在文档正文上设置事件侦听器,则在单击标有'popup-marker'的元素时将触发该事件侦听器 . 所以你必须在事件对象上调用 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个弹出式窗口 . 但我觉得这对用户来说会让人感到困惑,无论如何:-)

  • 5

    这更容易:

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

    我有类似的需求,发现这个great little extension of the Twitter Bootstrap Popover by Lee Carmichael, called BootstrapX - clickover . 他还有一些用法示例here . 基本上它会将popover更改为一个交互式组件,当您单击页面上的其他位置或弹出窗口中的关闭按钮时,该组件将关闭 . 这也将允许一次打开多个弹出窗口和一堆其他不错的功能 .

    Plugin can be found here .

    用法示例

    <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();
    
  • -3

    接受的解决方案给了我一些问题(点击打开的popover的'.popup-marker'元素使得popovers随后不起作用) . 我想出了另一个适合我的解决方案,它非常简单(我正在使用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!

  • 0

    阅读"Dismiss on next click"这里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>
    
  • 0

    我在使用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
        });
    });
    
  • 37

    所有现有的答案都相当薄弱,因为它们依赖捕获所有文档事件然后查找活动弹出窗口,或者修改对 .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);
    }
    
  • 0

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

    它是twitter bootstrap popover的扩展,可以非常简单地解决问题 .

  • 1

    出于某种原因,这里没有其他解决方案适用于我 . 然而,经过大量的故障排除后,我终于找到了这种方法,它完美地起作用(至少对我而言) .

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

    在我的情况下,我在表格中添加了一个弹出框,并将其绝对定位在单击的 td 上方/下方 . 表选择由jQuery-UI Selectable处理,所以我不确定这是否干扰 . 但是每当我在弹出窗口内单击时,我的单击处理程序(目标 $('.popover') )从未起作用,并且事件处理始终委托给 $(html) 单击处理程序 . 我'm fairly new to JS so perhaps I'我只是遗漏了什么?

    无论如何,我希望这有助于某人!

  • 1

    我给我所有的弹出器锚定了类 activate_popover . 我一次激活它们onload

    $('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完美搭配

  • 72

    虽然这里有很多解决方案,但是我知道是否有一些解决方案可以解决所有问题,但是我尝试了其中的3个并且它们有问题,比如点击它自己使它隐藏的popover,其他人那个如果我有另一个弹出按钮点击两个/多个弹出窗口仍然会出现(如在选定的解决方案中),如何, This one fixed it all

    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();
    });
    
  • 0

    这个解决方案对我来说非常好,如果它可以帮助:

    /**
    * 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;
            }        
        });
    });
    
  • -1

    这是我的解决方案,它的 Value 在于:

    // 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");
        }
    
      });
    });
    
  • 2

    稍微调整@David Wolever解决方案:

    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);
    }
    
  • 2

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

    一次打开多个弹出窗口或一次打开一个弹出窗口 .

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

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

  • 0

    这个就像一个魅力,我用它 .

    当您单击时它将打开弹出框,如果再次单击它将关闭,如果您单击弹出框外部,将关闭弹出窗口 .

    这也适用于超过1个popover .

    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();
    });
    
  • 18

    我会将焦点设置为新创建的弹出窗口并在模糊时将其移除 . 这样就不需要检查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');
        });
    
  • 1

    我这样做如下

    $("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');
                });
            });
        }
    });
    

    希望这可以帮助!

  • 97

    如果您正在尝试使用pjax的twitter bootstrap popover,这对我有用:

    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);
    });
    
  • 0

    @RayOnAir,我和以前的解决方案有同样的问题 . 我也接近@RayOnAir解决方案 . 改进的一件事就是在点击其他popover标记时关闭已经打开的popover . 所以我的代码是:

    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;
      }
    });
    
  • 0

    我发现这是上面提到的pbaron建议的修改解决方案,因为他的解决方案使用类'popup-marker'激活所有元素上的popover('hide') . 但是,当你使用popover()代替数据内容时,正如我在下面所做的那样,html弹出窗口内的任何点击实际上都会激活popover('hide'),这会立即关闭窗口 . 下面的方法遍历每个.popup-marker元素,如果父元素与被点击的.popup-marker的id相关,则首先发现,如果是,则不会隐藏它 . 所有其他div都隐藏了......

    $(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();
                });
            });
    
  • 0

    我想出了这个:

    我的场景在同一页面上包含更多弹出窗口,隐藏它们只是让它们不可见,因此,单击弹出窗口后面的项目是不可能的 . 我们的想法是将特定的popover-link标记为“active”,然后您可以简单地“切换”活动的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"
    
  • 0

    我试图为一个简单的问题做一个简单的解决方案 . 上面的帖子很好但是对于一个简单的问题来说很复杂 . 所以我做了一件简单的事情 . 刚刚添加了一个关闭按钮 . 它对我来说很完美 .

    $(".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;
        }
    
  • 0

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

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

    btn-popover class添加到打开弹出窗口的弹出框按钮/链接 . 此代码将在其外部单击时关闭弹出窗口 .

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

    一个更简单的解决方案,只是迭代所有的弹出窗口并隐藏,如果不是 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');
            }
        });
    });
    
  • 7
    $('.popForm').popover();
    
    $('.conteneurPopForm').on("click",".fermePopover",function(){
        $(".popForm").trigger("click");
    });
    

    要清楚,只需触发弹出窗口即可

  • 2

    另一个解决方案,它解决了我点击popover后代的问题:

    $(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');
        }
    });
    
  • 0

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

    这解决了我的问题 .

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

相关问题