web-dev-qa-db-fra.com

Comment puis-je garder le popover bootstrap en vie pendant le survol du popover?

J'utilise popover de Twitter boostrap pour créer une carte de survol pour afficher les informations des utilisateurs, et je déclenche une popover lors du contrôle de la souris jsfiddle ici. Je veux garder ce popover en vie pendant son vol stationnaire.

<a href="#" id="example" class="btn btn-danger" rel="popover" >hover for popover</a>

$('#example').popover({
        html : true,
        trigger : 'manual',
        content : function() {
            return '<div class="box"></div>';
        }
    });
$(document).on('mouseover', '#example', function(){
    $('#example').popover('show');
});
$(document).on('mouseleave', '#example', function(){
    $('#example').popover('hide');
});

Vous pouvez penser au travail de la carte de survol de Facebook. Je veux le faire de la même manière. Comment puis-je faire ceci?

93
vikas devde

Je suis venu après une autre solution à ceci ... voici le code

    $('.selector').popover({
        html: true,
        trigger: 'manual',
        container: $(this).attr('id'),
        placement: 'top',
        content: function () {
            $return = '<div class="hover-hovercard"></div>';
        }
    }).on("mouseenter", function () {
        var _this = this;
        $(this).popover("show");
        $(this).siblings(".popover").on("mouseleave", function () {
            $(_this).popover('hide');
        });
    }).on("mouseleave", function () {
        var _this = this;
        setTimeout(function () {
            if (!$(".popover:hover").length) {
                $(_this).popover("hide")
            }
        }, 100);
    });
76
vikas devde

Afficher ce code de travail dans Plunker

Petite modification (de la solution fournie par vikas) pour convenir à mon cas d'utilisation. 
1. Ouvrir l'événement Popover on Hover pour le bouton popover
2. Garder popover ouvert lorsque vous survolez la boîte popover
3. Fermez Popover sur Mouseleave pour le bouton Popover ou la boîte Popover.

$('.pop').popover({
    trigger: 'manual',
    html: true,
    animation: false
})
.on('mouseenter', function () {
    var _this = this;
    $(this).popover('show');
    $('.popover').on('mouseleave', function () {
        $(_this).popover('hide');
    });
}).on('mouseleave', function () {
    var _this = this;
    setTimeout(function () {
        if (!$('.popover:hover').length) {
            $(_this).popover('hide');
        }
    }, 300);
});

Joue avec Plunker

142
OkezieE

Voici ce que je pense: http://jsfiddle.net/WojtekKruszewski/Zf3m7/22/

Parfois, lorsque vous déplacez la souris d'un déclencheur popover à son contenu diagonalement, vous survolez les éléments ci-dessous. Je voulais gérer de telles situations - tant que vous atteignez le contenu popover avant le délai expiré, vous êtes en sécurité (la popover ne disparaîtra pas). Il nécessite l'option delay.

Ce hack annule fondamentalement la fonction Popover leave, mais appelle l'original (qui démarre le minuteur pour masquer la popover). Ensuite, il attache un auditeur unique à l'élément de contenu mouseenter popover.

Si la souris entre dans le popover, la minuterie est effacée. Ensuite, il passe à l'écoute de mouseleave lors du popover et s'il est déclenché, il appelle la fonction de congé d'origine afin qu'il puisse commencer à masquer le minuteur.

var originalLeave = $.fn.popover.Constructor.prototype.leave;
$.fn.popover.Constructor.prototype.leave = function(obj){
  var self = obj instanceof this.constructor ?
    obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
  var container, timeout;

  originalLeave.call(this, obj);

  if(obj.currentTarget) {
    container = $(obj.currentTarget).siblings('.popover')
    timeout = self.timeout;
    container.one('mouseenter', function(){
      //We entered the actual popover – call off the dogs
      clearTimeout(timeout);
      //Let's monitor popover content instead
      container.one('mouseleave', function(){
        $.fn.popover.Constructor.prototype.leave.call(self, self);
      });
    })
  }
};
28
Wojtek Kruszewski

J'ai utilisé le jeu de déclencheurs à hover et ai donné le jeu de conteneurs au #element, puis j'ai ajouté un emplacement de box à right.

Cela devrait être votre configuration: 

$('#example').popover({
    html: true,
    trigger: 'hover',
    container: '#example',
    placement: 'right',
    content: function () {
        return '<div class="box"></div>';
    }
});

et #example css a besoin de position:relative; vérifiez le jsfiddle ci-dessous:

https://jsfiddle.net/9qn6pw4p/1/

Édité

Ce violon a les deux liens qui fonctionnent sans problèmes http://jsfiddle.net/davidchase03/FQE57/4/

12
David Chase

Je pense qu'un moyen facile serait ceci:

$('.popover').each(function () {
                    var $this = $(this);
                    $this.popover({
                        trigger: 'hover',
                        content: 'Content Here',
                        container: $this
                    })
                });

De cette façon, le popover est créé à l'intérieur de l'élément cible lui-même. ainsi, lorsque vous déplacez votre souris sur la popover, elle reste toujours sur l'élément. Bootstrap 3.3.2 fonctionne bien avec cela. L’ancienne version peut avoir des problèmes d’animation, vous pouvez donc désactiver "animation: false"

8
Cu Lý

C'est ce que j'ai fait avec bootstrap popover avec l'aide d'autres bits sur le net. Obtient dynamiquement le titre et le contenu des différents produits affichés sur le site. Chaque produit ou popover reçoit un identifiant unique. Le popover disparaîtra à la sortie du produit ($ this .pop) ou du popover. Timeout est utilisé où affichera le popover jusqu'à la sortie via le produit au lieu de popover.

$(".pop").each(function () {
        var $pElem = $(this);
        $pElem.popover(
            {
                html: true,
                trigger: "manual",
                title: getPopoverTitle($pElem.attr("id")),
                content: getPopoverContent($pElem.attr("id")),
                container: 'body',
                animation:false
            }
        );
    }).on("mouseenter", function () {
        var _this = this;
        $(this).popover("show");
        console.log("mouse entered");
        $(".popover").on("mouseleave", function () {
            $(_this).popover('hide');
        });
    }).on("mouseleave", function () {
        var _this = this;
        setTimeout(function () {
            if (!$(".popover:hover").length) {
                $(_this).popover("hide");
            }
        }, 100);
    });
    function getPopoverTitle(target) {
        return $("#" + target + "_content > h3.popover-title").html();
    };

    function getPopoverContent(target) {
        return $("#" + target + "_content > div.popover-content").html();
    };
7
hoektoe

Voici une solution que j’ai conçue et qui semble bien fonctionner, tout en vous permettant également d’utiliser l’implémentation Bootstrap normale pour activer tous les popovers.

Violon original: https://jsfiddle.net/eXpressive/hfear592/

Porté à cette question:

<a href="#" id="example" class="btn btn-danger" rel="popover" >hover for popover</a>

$('#example').popover({
    html : true,
    trigger : 'hover',
    content : function() {
        return '<div class="box"></div>';
    }
}).on('hide.bs.popover', function () {
    if ($(".popover:hover").length) {
      return false;
    }                
}); 

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

Simple :)

$('[data-toggle="popover"]').popover( { "container":"body", "trigger":"focus", "html":true });
$('[data-toggle="popover"]').mouseenter(function(){
    $(this).trigger('focus');
});
1
edmc73

Je conviens que le meilleur moyen consiste à utiliser celui donné par: David Chase , Cu Ly et d’autres que le moyen le plus simple de procéder consiste à utiliser la propriété container: $(this) comme suit:

$(selectorString).each(
  var $this = $(this);
  $this.popover({
    html: true,
    placement: "top",
    container: $this,
    trigger: "hover",
    title: "Popover",
    content: "Hey, you hovered on element"
  });
);

Je tiens à souligner ici que le popover dans ce cas héritera de toutes les propriétés de l'élément actuel. Ainsi, par exemple, si vous faites cela pour un élément .btn (bootstrap), vous ne pourrez pas sélectionner de texte à l'intérieur du popover. Je voulais juste enregistrer ça puisque j'ai passé pas mal de temps à me cogner la tête.

1
forumulator

Vikas answer fonctionne parfaitement pour moi, j'ajoute ici un support pour le retard (afficher/masquer).

var popover = $('#example');
var options = {
    animation : true,
    html: true,
    trigger: 'manual',
    placement: 'right',
    delay: {show: 500, hide: 100}
};   
popover
    .popover(options)
    .on("mouseenter", function () {

        var t = this;
        var popover = $(this);    
        setTimeout(function () {

            if (popover.is(":hover")) {

                popover.popover("show");
                popover.siblings(".popover").on("mouseleave", function () {
                    $(t).popover('hide');
                });
            }
        }, options.delay.show);
    })
    .on("mouseleave", function () {
        var t = this;
        var popover = $(this);

        setTimeout(function () {
            if (popover.siblings(".popover").length && !popover.siblings(".popover").is(":hover")) {
                $(t).popover("hide")
            }
        }, options.delay.hide);
    });     

Aussi s'il vous plaît faites attention, j'ai changé:

if (!$(".popover:hover").length) {

avec:

if (popover.siblings(".popover").length && !popover.siblings(".popover").is(":hover")) {

de sorte qu'il se réfère exactement à cette popover ouverte, et à aucune autre (puisque maintenant, grâce au délai, plus d'un peut être ouvert en même temps)

1
user1993198

La réponse choisie fonctionne mais échouera si le popover est initialisé avec la variable body comme conteneur.

$('a').popover({ container: 'body' });

Une solution basée sur la réponse choisie est le code suivant qui doit être placé avant d'utiliser le popover.

var originalLeave = $.fn.popover.Constructor.prototype.leave;
$.fn.popover.Constructor.prototype.leave = function(obj) {
    var self = obj instanceof this.constructor ? obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type);
    originalLeave.call(this, obj);

    if (obj.currentTarget) {
        self.$tip.one('mouseenter', function() {
            clearTimeout(self.timeout);
            self.$tip.one('mouseleave', function() {
                $.fn.popover.Constructor.prototype.leave.call(self, self);
            });
        })
    }
};

La modification est minimale en utilisant self.$tip au lieu de traverser le DOM, en espérant que le popover sera toujours un frère de l'élément.

1
Rubens Mariuzzo

J'ai trouvé que la mouseleave ne se déclencherait pas lorsque des événements étranges se produiraient, comme le changement de focus de la fenêtre, puis que l'utilisateur revient au navigateur. Dans ce cas, mouseleave ne se déclenchera jamais tant que le curseur n’aura pas dépassé et ne quittera plus l’élément.

Cette solution proposée repose sur mouseenter sur l'objet window. Elle disparaît dès que la souris est déplacée n'importe où ailleurs sur la page.

Cela a été conçu pour fonctionner avec plusieurs éléments sur la page qui vont la déclencher (comme dans un tableau).

var allMenus = $(".menus");
allMenus.popover({
    html: true,
    trigger: "manual",
    placement: "bottom",
    content: $("#menuContent")[0].outerHTML
}).on("mouseenter", (e) => {
    allMenus.not(e.target).popover("hide");
    $(e.target).popover("show");
    e.stopPropagation();
}).on("shown.bs.popover", () => {
    $(window).on("mouseenter.hidepopover", (e) => {
        if ($(e.target).parents(".popover").length === 0) {
            allMenus.popover("hide");
            $(window).off("mouseenter.hidepopover");
        }
    });
});
0
Gabriel Luci
        $(function() {
            $("[data-toggle = 'popover']").popover({
                placement: 'left',
                html: true,
                trigger: "  focus",
            }).on("mouseenter", function() {
                var _this = this;
                $(this).popover("show");
                $(this).siblings(".popover").on("mouseleave", function() {
                    $(_this).popover('hide');
                });
            }).on("mouseleave", function() {
                var _this = this;
                setTimeout(function() {
                    if (!$(".popover:hover").length) {
                        $(_this).popover("hide")
                    }
                }, 100);
            });
        }); 
0
Dinesh Sarak

Même chose pour les info-bulles:

Pour moi, la solution suivante fonctionne parce qu’elle n’ajoute pas d’écouteurs d’événements à chaque 'mouseenter' et qu’il est possible de revenir en arrière sur l’élément d’info-bulle, ce qui la maintient active.

$ ->

  $('.element').tooltip({
    html: true,
    trigger: 'manual'
  }).
  on 'mouseenter', ->
    clearTimeout window.tooltipTimeout
    $(this).tooltip('show') unless $('.tooltip:visible').length > 0
  .
  on 'mouseleave', ->
    _this = this
    window.tooltipTimeout = setTimeout ->
      $(_this).tooltip('hide')
    , 100

$(document).on 'mouseenter', '.tooltip', ->
  clearTimeout window.tooltipTimeout

$(document).on 'mouseleave', '.tooltip', ->
  trigger = $($(this).siblings('.element')[0])
  window.tooltipTimeout = setTimeout ->
    trigger.tooltip('hide')
  , 100
0
phlppn

Ce sera plus flexible avec hover():

$(".my-popover").hover(
    function() {  // mouse in event
        $this = $(this);
        $this.popover({
            html: true,
            content: "Your content",
            trigger: "manual",
            animation: false
            });
        $this.popover("show");
        $(".popover").on("mouseleave", function() {
            $this.popover("hide");
        });
    },
    function() {  // mouse out event
        setTimeout(function() {
            if (!$(".popover:hover").length) {
                $this.popover("hide");
            }
        }, 100);
    } 
)
0
Grey Li

Cette solution a bien fonctionné pour moi: (maintenant son pare-balles) ;-)

function enableThumbPopover() {
    var counter;

    $('.thumbcontainer').popover({
        trigger: 'manual',
        animation: false,
        html: true,
        title: function () {
            return $(this).parent().find('.thumbPopover > .title').html();
        },
        content: function () {
            return $(this).parent().find('.thumbPopover > .body').html();
        },
        container: 'body',
        placement: 'auto'
    }).on("mouseenter",function () {
        var _this = this; // thumbcontainer

        console.log('thumbcontainer mouseenter')
        // clear the counter
        clearTimeout(counter);
        // Close all other Popovers
        $('.thumbcontainer').not(_this).popover('hide');

        // start new timeout to show popover
        counter = setTimeout(function(){
            if($(_this).is(':hover'))
            {
                $(_this).popover("show");
            }
            $(".popover").on("mouseleave", function () {
                $('.thumbcontainer').popover('hide');
            });
        }, 400);

    }).on("mouseleave", function () {
        var _this = this;

        setTimeout(function () {
            if (!$(".popover:hover").length) {
                if(!$(this).is(':hover'))
                {
                    $(_this).popover('hide');
                }
            }
        }, 200);
    });
}
0
Johannes Ferner

Ceci est mon code pour afficher les info-bulles dynamiques avec délai et chargé par ajax.

$(window).on('load', function () {
    generatePopovers();
    
    $.fn.dataTable.tables({ visible: true, api: true }).on('draw.dt', function () {
        generatePopovers();
    });
});

$(document).ajaxStop(function () {
    generatePopovers();
});
function generatePopovers() {
var popover = $('a[href*="../Something.aspx"]'); //locate the elements to popover

popover.each(function (index) {
    var poplink = $(this);
    if (poplink.attr("data-toggle") == null) {
        console.log("RENDER POPOVER: " + poplink.attr('href'));
        poplink.attr("data-toggle", "popover");
        poplink.attr("data-html", "true");
        poplink.attr("data-placement", "top");
        poplink.attr("data-content", "Loading...");
        poplink.popover({
            animation: false,
            html: true,
            trigger: 'manual',
            container: 'body',
            placement: 'top'
        }).on("mouseenter", function () {
            var thispoplink = poplink;
            setTimeout(function () {
                if (thispoplink.is(":hover")) {
                    thispoplink.popover("show");
                    loadDynamicData(thispoplink); //load data by ajax if you want
                    $('body .popover').on("mouseleave", function () {
                        thispoplink.popover('hide');
                    });
                }
            }, 1000);
        }).on("mouseleave", function () {
            var thispoplink = poplink;
            setTimeout(function () {
                if (!$("body").find(".popover:hover").length) {
                    thispoplink.popover("hide");
                }
            }, 100);
        });
    }
});
function loadDynamicData(popover) {
    var params = new Object();
    params.somedata = popover.attr("href").split("somedata=")[1]; //obtain a parameter to send
    params = JSON.stringify(params);
    //check if the content is not seted
    if (popover.attr("data-content") == "Loading...") {
        $.ajax({
            type: "POST",
            url: "../Default.aspx/ObtainData",
            data: params,
            contentType: "application/json; charset=utf-8",
            dataType: 'json',
            success: function (data) {
                console.log(JSON.parse(data.d));
                var dato = JSON.parse(data.d);
                if (dato != null) {
                    popover.attr("data-content",dato.something); // here you can set the data returned
                    if (popover.is(":hover")) {
                        popover.popover("show"); //use this for reload the view
                    }
                }
            },

            failure: function (data) {
                itShowError("- Error AJAX.<br>");
            }
        });
    }
}
0
Giuliano