Можем ли мы получить popovers для увольнения так же, как модалы, т.е. закрыть их, когда пользователь нажимает где-то за их пределами?
К сожалению, я не могу просто использовать настоящий модальный вместо popover, потому что модальная позиция означает: исправлена, и это больше не будет popover.: (
Обновление: Несколько более надежное решение: http://jsfiddle.net/mattdlockyer/C5GBU/72/
Для кнопок, содержащих только текст:
$('body').on('click', function (e) {
//did not click a popover toggle or popover
if ($(e.target).data('toggle') !== 'popover'
&& $(e.target).parents('.popover.in').length === 0) {
$('[data-toggle="popover"]').popover('hide');
}
});
Для кнопок, содержащих значки, используйте (этот код имеет ошибку в Bootstrap 3.3.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');
}
});
Для JS Generated Popovers Используйте '[data-original-title]'
вместо '[data-toggle="popover"]'
Предостережение: Вышеупомянутое решение позволяет сразу открывать несколько popovers.
Один постер в любое время:
Обновление: Bootstrap 3.0.x, см. код или скрипт http://jsfiddle.net/mattdlockyer/C5GBU/2/
$('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');
}
});
});
Это обрабатывает закрытие всплывающих окон, которые уже открыты и не нажаты, или их ссылки не были нажаты.
Обновление: Bootstrap 3.3.6, см. скрипку
Исправлена проблема, когда после закрытия требуется 2 щелчка для повторного открытия
$(document).on('click', function (e) {
$('[data-toggle="popover"],[data-original-title]').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('bs.popover')||{}).inState||{}).click = false // fix for BS 3.3.6
}
});
});
$('html').on('mouseup', function(e) {
if(!$(e.target).closest('.popover').length) {
$('.popover').each(function(){
$(this.previousSibling).popover('hide');
});
}
});
Это закрывает все popovers, если вы нажимаете где-либо, кроме как на popover
ОБНОВЛЕНИЕ для Bootstrap 4.1
$("html").on("mouseup", function (e) {
var l = $(e.target);
if (l[0].className.indexOf("popover") == -1) {
$(".popover").each(function () {
$(this).popover("hide");
});
}
});
Самая простая, наиболее безопасная версия, работает с любой версией начальной загрузки.
Демо: http://jsfiddle.net/guya/24mmM/
Демонстрация 2: не отклонение при нажатии внутри содержимого popover http://jsfiddle.net/guya/fjZja/
Демо 3: Несколько popovers: http://jsfiddle.net/guya/6YCjW/
Просто вызов этой строки убьет все popovers:
$('[data-original-title]').popover('hide');
Отклонить все popovers при нажатии на внешний вид с помощью этого кода:
$('html').on('click', function(e) {
if (typeof $(e.target).data('original-title') == 'undefined') {
$('[data-original-title]').popover('hide');
}
});
Фрагмент выше прикрепляет событие click на теле. Когда пользователь нажимает на popover, он будет вести себя как обычно. Когда пользователь нажимает на то, что не является popover, оно закрывает все popovers.
Он также будет работать с popovers, которые инициируются Javascript, в отличие от некоторых других примеров, которые не будут работать. (см. демонстрацию)
Если вы не захотите уклоняться при нажатии внутри содержимого popover, используйте этот код (см. ссылку на 2-ю демо):
$('html').on('click', function(e) {
if (typeof $(e.target).data('original-title') == 'undefined' && !$(e.target).parents().is('.popover.in')) {
$('[data-original-title]').popover('hide');
}
});
Это в основном не очень сложно, но есть некоторая проверка, чтобы избежать сбоев.
var $poped = $('someselector');
// Trigger for the popover
$poped.each(function() {
var $this = $(this);
$this.on('hover',function() {
var popover = $this.data('popover');
var shown = popover && popover.tip().is(':visible');
if(shown) return; // Avoids flashing
$this.popover('show');
});
});
// Trigger for the hiding
$('html').on('click.popover.data-api',function() {
$poped.popover('hide');
});
popover()
по нажатию, а не при наведении курсора?
С помощью бутстрапа 2.3.2 вы можете установить триггер на "фокус", и он просто работает:
$('#el').popover({trigger:'focus'});
Ни один из предполагаемых высоко разрешенных решений не работал у меня правильно. Каждый из них приводит к ошибке, когда после открытия и закрытия (щелкнув по другим элементам) popover в первый раз, он не открывается снова, пока вы не сделаете два клика на триггерной ссылке вместо одной.
Итак, я немного изменил его:
$(document).on('click', function (e) {
var
$popover,
$target = $(e.target);
//do nothing if there was a click on popover content
if ($target.hasClass('popover') || $target.closest('.popover').length) {
return;
}
$('[data-toggle="popover"]').each(function () {
$popover = $(this);
if (!$popover.is(e.target) &&
$popover.has(e.target).length === 0 &&
$('.popover').has(e.target).length === 0)
{
$popover.popover('hide');
} else {
//fixes issue described above
$popover.popover('toggle');
}
});
})
Я сделал jsfiddle, чтобы показать вам, как это сделать:
Идея состоит в том, чтобы показать popover, когда вы нажимаете кнопку, и скрывать popover, когда вы нажимаете кнопку за пределами кнопки.
<a id="button" href="#" class="btn btn-danger">Click for popover</a>
$('#button').popover({
trigger: 'manual',
position: 'bottom',
title: 'Example',
content: 'Popover example for SO'
}).click(function(evt) {
evt.stopPropagation();
$(this).popover('show');
});
$('html').click(function() {
$('#button').popover('hide');
});
просто добавьте этот атрибут с элементом
data-trigger="focus"
Модифицированное принятое решение. То, что я испытал, было то, что после того, как некоторые popovers были спрятаны, их нужно было бы дважды щелкнуть, чтобы снова появиться. Вот что я сделал, чтобы гарантировать, что popover ('hide') не вызывается на уже скрытые popovers.
$('body').on('click', function (e) {
$('[data-original-title]').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) {
var popoverElement = $(this).data('bs.popover').tip();
var popoverWasVisible = popoverElement.is(':visible');
if (popoverWasVisible) {
$(this).popover('hide');
$(this).click(); // double clicking required to reshow the popover if it was open, so perform one click now
}
}
});
});
Согласно http://getbootstrap.com/javascript/#popovers,
<button type="button" class="popover-dismiss" data-toggle="popover" title="Dismissible popover" data-content="Popover Content">Dismissible popover</button>
Используйте триггер фокуса, чтобы отклонять popovers при следующем щелчке, который делает пользователь.
$('.popover-dismiss').popover({
trigger: 'focus'
})
<a>
, а не тег <button>
, и Вы также должны включить атрибуты role="button"
и tabindex
. " Вы пробовали это с этими спецификациями?
Это опаздывает на вечеринку... но я думал, что поделюсь ею. Мне нравится popover, но у него так мало встроенных функций. Я написал расширение бутстрапа .bubble(), это все, что мне хотелось бы, чтобы это было. Четыре способа уволить. Нажмите снаружи, переключитесь на ссылку, нажмите X и нажмите escape.
Он позиционируется автоматически, чтобы он никогда не покидал страницу.
https://github.com/Itumac/bootstrap-bubble
Это не беспроигрышная самопомощь... Я много раз забирал у других людей код в своей жизни, я хотел предложить свои собственные усилия. Дайте ему вихрь и посмотрите, работает ли оно для вас.
Это задано перед here. Тот же ответ, который я дал, по-прежнему применяется:
У меня была аналогичная потребность, и я нашел это большое небольшое расширение Twitter Bootstrap Popover от Lee Carmichael, названное BootstrapX - clickover. Он также имеет некоторые примеры использования здесь. В основном это изменит popover на интерактивный компонент, который закроется, когда вы нажмете в другом месте на странице или на кнопке закрытия внутри popover. Это также позволит открывать сразу несколько popovers и множество других приятных функций.
это решение избавляется от досадного второго щелчка при показе popover во второй раз
с помощью Bootstrap v3.3.7
$('body').on('click', function (e) {
$('.popover').each(function () {
var popover = $(this).data('bs.popover');
if (!popover.$element.is(e.target)) {
popover.inState.click = false;
popover.hide();
}
});
});
Bootstrap изначально поддерживает это:
Конкретная разметка, необходимая для перехода к следующему клику
Для правильного кросс-браузерного и кросс-платформенного поведения вы должны использовать тег
<a>
, а не тег<button>
, а также должны включать атрибутыrole="button"
иtabindex
.
Мы выяснили, что у нас была проблема с решением от @mattdlockyer (спасибо за решение!). При использовании свойства selector для конструктора popover, подобного этому...
$(document.body').popover({selector: '[data-toggle=popover]'});
... предлагаемое решение для BS3 не будет работать. Вместо этого он создает второй экземпляр popover, локальный для своего $(this)
. Вот наше решение, чтобы предотвратить это:
$(document.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) {
var bsPopover = $(this).data('bs.popover'); // Here where the magic happens
if (bsPopover) bsPopover.hide();
}
});
});
Как уже упоминалось, $(this).popover('hide');
создаст второй экземпляр из-за делегированного прослушивателя. Решение предоставило только скрытые popovers, которые уже были созданы.
Надеюсь, я смогу сэкономить вам время.
Кажется, что метод 'hide' не работает, если вы создаете popover с делегированием селектора, вместо этого нужно использовать "destroy".
Я сделал это так:
$('body').popover({
selector: '[data-toggle="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('destroy');
}
});
});
Вы также можете использовать пузырьки событий, чтобы удалить всплывающее окно из DOM. Это немного грязно, но отлично работает.
$('body').on('click touchstart', '.popover-close', function(e) {
return $(this).parents('.popover').remove();
});
В html добавьте класс .popover-close к содержимому внутри popover, которое должно закрыть popover.
jQuery("#menu").click(function(){ return false; });
jQuery(document).one("click", function() { jQuery("#menu").fadeOut(); });
jQuery(document).one()
работает только один раз.
Я пробовал многие из предыдущих ответов, на самом деле для меня ничего не работает, но это решение получило:
https://getbootstrap.com/docs/3.3/javascript/#dismiss-on-next-click
Они рекомендуют использовать якорный тэг not button и позаботиться о параметрах role = "button" + data-trigger = "focus" + tabindex = "0".
Пример:
<a tabindex="0" class="btn btn-lg btn-danger" role="button" data-toggle="popover"
data-trigger="focus" title="Dismissible popover" data-content="amazing content">
Dismissible popover</a>
Просто добавьте этот атрибут в элемент html, чтобы закрыть popover в следующий клик.
data-trigger="focus"
ссылка из https://getbootstrap.com/docs/3.3/javascript/#popovers
проверено с 3.3.6, а второй щелчок в порядке
$('[data-toggle="popover"]').popover()
.click(function () {
$(this).popover('toggle');
});;
$(document).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');
}
});
});
Я просто удаляю другие активные popovers перед показом нового popover (bootstrap 3):
$(".my-popover").popover();
$(".my-popover").on('show.bs.popover',function () {
$('.popover.in').remove();
});
Есть проблема с последним обновлением принятого ответа: Если у вас есть всплывающие подсказки, и вы открываете popover, а затем нажимаете на элемент, содержащий подсказку, текст всплывающей подсказки будет отображаться как popover для.
Чтобы предотвратить это, просто добавьте
if ($(this).data('bs.popover')) {
внутри оператора if (или добавить его в конкатенацию с && в оператор if)
// only show one popover at the time and hide on clicking outside
$(document).on('click', function (e) {
$('[data-toggle="popover"],[data-original-title]').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) {
if ($(this).data('bs.popover')) {
(($(this).popover('hide').data('bs.popover') || {}).inState || {}).click = false // fix for BS 3.3.6
}
}
});
});
$(document).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
}
});
});
Ответ работает очень хорошо, просто добавьте директиву angular в случае, если вы используете angular, как я:
app.directive('popover', ['$document', function($document) {
return {
restrict: 'EA',
link: function(scope, elem, attrs) {
$(document).ready(function() {
$('[data-toggle="popover"]').popover();
});
elem.bind('click', function(e) {
$('#notification').popover('toggle');
})
$('body').on('click', function (e) {
//the 'is' for buttons that trigger popups
//the 'has' for icons within a button that triggers a popup
if (!elem.is(e.target)
&& elem.has(e.target).length === 0
&& $('.popover').has(e.target).length === 0) {
elem.popover('hide');
}
});
}
};
}]);
Код html:
<a popover tabindex="0" role="button"
id="notification"
data-toggle="popover" data-trigger="manual"
data-container="body" data-placement="bottom"
data-content="This is a popover">
Popover button
</a>
Это должно быть так же просто, как использовать data-trigger='click focus'
, потому что в соответствии с bootstrap:
Как запускается popover - нажмите | парить | фокус | руководство. Вы можете передавать несколько триггеров; отделите их пространством. руководство не может быть объединено с каким-либо другим триггером.
Однако использование клика и фокуса вместе не работает для меня по неизвестной причине, вместо этого я должен вручную переключать его.
$('html').on('click.popover', function (e) {
var allpopins = $('.popover.in');
if (allpopins.has(e.target).length > 0 &&
!$('.btn', allpopins).is(e.target))
return;
// recognise pop-up
var id = $(e.target).attr('aria-describedby');
var popin = $("#" + id);
//on any button click in entire pop-up hide this pop-ups
$(popin).on(".btn", function () { popin.remove(); });
// on any place out of entire popup hide all pop-ups
$('.popover.in').not(popin).remove();
});
Это мое лучшее решение для производительности. Приветствия.
Ответ от @guya работает, если у вас нет что-то вроде datepicker или timepicker в popover. Чтобы это исправить, это то, что я сделал.
if (typeof $(e.target).data('original-title') === 'undefined' &&
!$(e.target).parents().is('.popover.in')) {
var x = $(this).parents().context;
if(!$(x).hasClass("datepicker") && !$(x).hasClass("ui-timepicker-wrapper")){
$('[data-original-title]').popover('hide');
}
}
У меня возникали проблемы с решением mattdlockyer, потому что я динамически настраивал ссылки на popover, используя следующий код:
$('body').popover({
selector : '[rel="popover"]'
});
Поэтому мне пришлось изменить его так. Для меня было много проблем:
$('html').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('destroy');
}
});
});
Помните, что уничтожение избавляется от элемента, поэтому селекторная часть важна при инициализации popovers.
Попробуйте это, это скроется, щелкнув снаружи.
$('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');
}
});
});
Взяв код Matt Lockyer, я сделал простую reset, поэтому dom не покрывается элементом в hide.
Мэтт код: http://mattlockyer.com/2013/04/08/close-a-twitter-bootstrap-popover-when-clicking-outside/
Fiddle: http://jsfiddle.net/mrsmith/Wd2qS/
$('body').on('click', function (e) {
//hide popover from dom to prevent covering elements
$('.popover').css('display', 'none');
//bring popover back if trigger element is clicked
$('[data-toggle="popover"]').each(function () {
if ($(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
$('.popover').css('display', 'block');
}
});
//hide popover with .popover method
$('[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');
}
});
});
Я придумал это: Мой сценарий включал в себя больше popovers на одной странице, и их скрытие просто сделало их невидимыми, и из-за этого щелчок по элементам позади popover не был возможен. Идея состоит в том, чтобы отметить конкретную popover-ссылку как "активную", а затем вы можете просто "переключить" активный 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"
Хорошо, это моя первая попытка ответить на что-то в stackoverflow, поэтому здесь ничего не происходит: P
Похоже, что не совсем ясно, что эта функциональность действительно работает из коробки в последнем загрузочном блоке (ну, если вы готовы пойти на компромисс, где пользователь может нажать. Я не уверен, что вам нужно поместите 'click hover' per-se, но на iPad, щелчок работает как переключатель.
Конечный результат: на рабочем столе вы можете навести указатель мыши или щелкнуть (большинство пользователей будет нависнуть). На сенсорном устройстве прикосновение к элементу вызовет его, и прикосновение к нему снова снимет его. Конечно, это небольшой компромисс от вашего первоначального требования, но по крайней мере ваш код теперь более чистый:)
$( "мой-поповер" ). Поповер ({ триггер: 'click hover' });
Этот подход гарантирует, что вы можете закрыть popover, щелкнув в любом месте страницы. Если вы нажмете на другой кликабельный объект, он скрывает все остальные popovers. Анимация: false требуется другое, вы получите ошибку jquery.remove в консоли.
$('.clickable').popover({
trigger: 'manual',
animation: false
}).click (evt) ->
$('.clickable').popover('hide')
evt.stopPropagation()
$(this).popover('show')
$('html').on 'click', (evt) ->
$('.clickable').popover('hide')
demo: http://jsfiddle.net/nessajtr/yxpM5/1/
var clickOver = clickOver || {};
clickOver.uniqueId = $.now();
clickOver.ClickOver = function (selector, options) {
var self = this;
//default values
var isVisible, clickedAway = false;
var callbackMethod = options.content;
var uniqueDiv = document.createElement("div");
var divId = uniqueDiv.id = ++clickOver.uniqueId;
uniqueDiv.innerHTML = options.loadingContent();
options.trigger = 'manual';
options.animation = false;
options.content = uniqueDiv;
self.onClose = function () {
$("#" + divId).html(options.loadingContent());
$(selector).popover('hide')
isVisible = clickedAway = false;
};
self.onCallback = function (result) {
$("#" + divId).html(result);
};
$(selector).popover(options);
//events
$(selector).bind("click", function (e) {
$(selector).filter(function (f) {
return $(selector)[f] != e.target;
}).popover('hide');
$(selector).popover("show");
callbackMethod(self.onCallback);
isVisible = !(clickedAway = false);
});
$(document).bind("click", function (e) {
if (isVisible && clickedAway && $(e.target).parents(".popover").length == 0) {
self.onClose();
isVisible = clickedAway = false;
} else clickedAway = true;
});
}
это мое решение для него.
Так просто, просто добавьте:
$('body').on('click', function() {
$('.popover').each(function() {
$(this).popover('hide');
});
});
$("body").find('.popover').removeClass('in');