Как я могу закрыть Twitter Bootstrap popover с помощью щелчка из любого места (еще) на странице?



в настоящее время я использую popovers с Twitter Bootstrap, инициированный следующим образом:



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


Как вы можете видеть, они запускаются вручную и нажав кнопку Далее .popup-маркер (который является div с фоновым изображением) переключает всплывающее окно. Это отлично работает, но я хотел бы также иметь возможность закрыть popover с щелчком мыши в любом месте на странице (но не на самом popover!).



Я пробовал несколько разных вещей, включая следующие, но без результатов это:



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


как я могу закрыть popover с щелчком мыши в другом месте на странице, но не с щелчком на самом popover?

583   30  

30 ответов:

предполагая, что только один поповер может быть виден в любое время, вы можете использовать набор флагов, чтобы отметить, когда есть видимый поповер, и только затем скрыть их.

Если вы установите прослушиватель событий в теле документа, он будет срабатывать при нажатии на элемент, отмеченный "всплывающим маркером". Так что вам придется позвонить 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 popovers одновременно. Но я думаю, что это было бы запутанным для пользователя, в любом случае :-)

Это еще проще :

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

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

у меня была аналогичная потребность, и я нашел это большое небольшое расширение Twitter Bootstrap Popover от Lee Carmichael, называемое BootstrapX-clickover. У него также есть несколько примеров использования здесь. В основном это изменит popover в интерактивный компонент, который закроется, когда вы нажмете в другом месте на странице или на кнопку закрытия в popover. Это также позволит открыть сразу несколько всплывающих окон и кучу других приятных особенности.

плагин можно найти здесь.

пример использования

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

принятое решение дало мне некоторые проблемы (нажав на '.всплывающее окно-маркер элемента в открывшемся всплывающем окне сделала эклеры, а не после работы). Я придумал другое решение, которое отлично работает для меня и это довольно просто (я использую 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!

читать "уволить на следующий пункт" здесь http://getbootstrap.com/javascript/#popovers

вы можете использовать триггер фокусировки, чтобы отклонить всплывающие окна при следующем щелчке, но вы должны использовать<a> тег, а не <button> тег, и вы также должны включать в себя ...

пример:

<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().

гораздо лучший подход-это слушать 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);
}

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

Это расширение twitter bootstrap popover и решит проблему очень просто.

по какой-то причине ни одно из других решений здесь не работало для меня. Однако после большого количества устранения неполадок я, наконец, пришел к этому методу, который отлично работает (по крайней мере, для меня).

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

в моем случае я добавлял popover к таблице и абсолютно позиционировал его выше / ниже td, который был выбран. Выбор таблицы обрабатывался jQuery-UI, поэтому я не уверен, что это мешало. Однако всякий раз, когда я нажимал внутри popover мой обработчик кликов который нацелен $('.popover') никогда не работал и обработка событий всегда была делегирована $(html) нажмите кнопку обработчик. Я довольно новичок в JS, так что, возможно, я просто что-то упускаю?

в любом случае я надеюсь, что это поможет кому-то!

Я даю все мои popovers якоря класса 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

несмотря на то, что здесь есть много решений, я также хотел бы предложить свое, я не знаю, есть ли там какое-то решение, которое решает все это, но я попробовал 3 из них, и у них были проблемы, например, щелчок по popover IT self заставляет его скрывать, другие, которые если бы у меня были другие кнопки popover, нажали бы оба / несколько popovers все равно появятся (как в выбранном решении), как бы то ни было,этот исправил все это

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

вот решение, что работал очень хорошо для меня, если это может помочь :

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

вот мое решение, для чего оно стоит:

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

  });
});

У меня были некоторые проблемы, чтобы заставить его работать на 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 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);
}

этот вопрос также был задан здесь, и мой ответ предоставляет не только способ понять методы обхода jQuery DOM, но и 2 варианта обработки закрытия всплывающих окон, нажав снаружи.

откройте несколько всплывающих окон одновременно или по одному всплывающему окну за раз.

плюс эти небольшие фрагменты кода могут обрабатывать закрытие кнопок, содержащих значки!

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

это работает как шарм, и я использую его.

Он откроет поповер, когда вы нажмете, и если вы нажмете еще раз, он закроется, также если вы нажмете за пределами поповера, поповер будет закрыт.

Это также работает с более чем 1 пирог.

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

Я бы поставил фокус на вновь созданное всплывающее окно и удалил его при размытии. Таким образом, не нужно проверять, какой элемент 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');
    });

Я делаю это, как показано ниже

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

надеюсь, что это помогает!

Если вы пытаетесь использовать twitter bootstrap popover с pjax, это сработало для меня:

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

@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;
  }
});

Я обнаружил, что это модифицированное решение предложения pbaron выше, потому что его решение активировало popover('hide') на всех элементах с классом 'popup-marker'. Однако, когда вы используете popover () для содержимого html вместо содержимого данных, как я делаю ниже, любые клики внутри этого всплывающего окна html фактически активируют popover ('hide'), который быстро закрывает окно. Этот метод ниже повторяет каждый из них .всплывающее окно-маркер элемент и обнаруживает сначала, если родитель связан с .popup-идентификатор маркера, который был нажат, и если да, то не скрывает его. Все остальные дивы скрыты...

        $(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-ссылку как "активный", а затем вы можете просто "переключить" активный 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"

Я пытаюсь сделать простое решение для простой проблемы. Выше сообщения хороши, но так сложно для простого вопроса. Поэтому я сделал простую вещь. Просто добавлена кнопка закрытия. Он идеально подходит для меня.

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

добавить 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");
});

чтобы было понятно, просто вызвать диалоговое окно

другое решение, оно охватывало проблему, которую я имел с щелчком потомков 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');
    }
});

попробовать data-trigger="focus" вместо "click".

это решило проблему для меня.

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

Comments

    Ничего не найдено.