227 votes

Empêcher l'apparition de la souris lors du survol d'un élément enfant d'un div absolu parent SANS jQuery

J'ai des difficultés avec le onmouseout dans un div positionné de façon absolue. Lorsque la souris touche un élément enfant dans la division, l'événement mouseout se déclenche, mais je ne veux pas qu'il se déclenche tant que la souris n'est pas sortie de la division parent, absolue.

Comment puis-je empêcher le mouseout de se déclencher lorsqu'il touche un élément enfant SANS jquery.

Je sais que cela a quelque chose à voir avec le bouillonnement des événements, mais je n'ai pas réussi à trouver comment résoudre ce problème.

J'ai trouvé un poste similaire ici : Comment désactiver les événements de mouseout déclenchés par les éléments enfants ?

Cependant, cette solution utilise jQuery.

1 votes

J'ai fini par résoudre le problème en utilisant un délai d'attente et en l'effaçant au survol des éléments enfants.

0 votes

Bonjour, j'ai regardé votre démo mais lorsque je passe sur les éléments dans le panneau en bas à droite, rien ne se passe ?

1 votes

J'ai trouvé cette réponse si vous cherchez à empêcher un mouseout sur l'événement parent lorsque vous passez la souris sur un élément enfant : javascript mouseover/mouseout .

134voto

Zach Saucier Points 11345

Pour une solution CSS pure plus simple qui fonctionne dans la plupart des cas, on pourrait supprimer les enfants pointer-events en les réglant sur none

.parent * {
     pointer-events: none;
}

Support des navigateurs : IE11+.

4 votes

Génial ! Je viens de résoudre mon problème !

4 votes

Cela devrait être la première ou au moins la deuxième réponse. J'étais prêt à me débarrasser des écouteurs d'événements et cela a totalement résolu mon problème. C'est si simple !

22 votes

Cela empêche le mouseout de se déclencher, mais pour moi, cela empêche également l'enfant actuel d'être cliqué comme une sélection dans le menu, ce qui est le but du menu.

102voto

Amjad Masad Points 2294
function onMouseOut(event) {
        //this is the original element the event handler was assigned to
        var e = event.toElement || event.relatedTarget;
        if (e.parentNode == this || e == this) {
           return;
        }
    alert('MouseOut');
    // handle mouse event here!
}

document.getElementById('parent').addEventListener('mouseout',onMouseOut,true);

J'ai fait une démo rapide en JsFiddle, avec toutes les CSS et HTML nécessaires, regardez-la...

EDIT CORRECTION du lien pour la prise en charge des navigateurs croisés http://jsfiddle.net/RH3tA/9/

NOTE que cela ne vérifie que le parent immédiat, si le div parent a des enfants imbriqués, vous devez d'une manière ou d'une autre parcourir les éléments parents à la recherche de l'"élément originel".

EDIT exemple pour les enfants imbriqués

EDIT Corrigé pour les navigateurs croisés

function makeMouseOutFn(elem){
    var list = traverseChildren(elem);
    return function onMouseOut(event) {
        var e = event.toElement || event.relatedTarget;
        if (!!~list.indexOf(e)) {
            return;
        }
        alert('MouseOut');
        // handle mouse event here!
    };
}

//using closure to cache all child elements
var parent = document.getElementById("parent");
parent.addEventListener('mouseout',makeMouseOutFn(parent),true);

//quick and dirty DFS children traversal, 
function traverseChildren(elem){
    var children = [];
    var q = [];
    q.push(elem);
    while (q.length > 0) {
      var elem = q.pop();
      children.push(elem);
      pushAll(elem.children);
    }
    function pushAll(elemArray){
      for(var i=0; i < elemArray.length; i++) {
        q.push(elemArray[i]);
      }
    }
    return children;
}

Et un nouveau JSFiddle , EDIT lien actualisé

1 votes

Vous devriez ajouter un événement mouseout à l'infidèle pour qu'il puisse être testé. Une alerte ou autre devrait faire l'affaire.

0 votes

Désolé, il semble que vous avez alert('MouseOut'), mais cela ne fonctionne pas pour moi ? J'ai lancé l'option sans bibliothèque JS.

0 votes

Testé sur safari et chrome, mais devrait fonctionner sur tout ! quel est votre navigateur ?

29voto

Sam-Elie Points 331

Voici une solution plus élégante basée sur ce qui suit. Elle tient compte des événements qui remontent de plus d'un niveau d'enfants. Elle tient également compte des problèmes liés aux navigateurs.

function onMouseOut(this, event) {
//this is the original element the event handler was assigned to
   var e = event.toElement || event.relatedTarget;

//check for all children levels (checking from bottom up)
while(e && e.parentNode && e.parentNode != window) {
    if (e.parentNode == this||  e == this) {
        if(e.preventDefault) e.preventDefault();
        return false;
    }
    e = e.parentNode;
}

//Do something u need here
}

document.getElementById('parent').addEventListener('mouseout',onMouseOut,true);

0 votes

Sam Elie, cela semble ne pas fonctionner sur IE, Safari ou Opera. Avez-vous une version multi-navigateur de ce script ? Il fonctionne comme un charme dans Firefox et Chrome. Merci.

1 votes

Lorsque je colle la fonction ci-dessus dans mon script, Dreamweaver et FF jettent une erreur sur la première ligne, "function onMouseOut(this, event) {". Il semble que vous ne soyez pas autorisé à mettre "this" comme paramètre. Je suppose que cela fonctionne en quelque sorte lorsque je ne mets pas "this" dans les paramètres d'entrée, mais je n'en suis pas sûr, car "je ne sais pas ce que je ne sais pas".

1 votes

J'ai également eu le même problème dans Chrome sur la même ligne, à l'exclusion de this de la ligne de définition de la fonction mentionnée par @GregoryLewis a résolu le problème. Pour une meilleure prise en charge des navigateurs, essayez ceci : if (window.addEventListener){ document.getElementById('parent').addEventListener('mouseout',onMouseOut,true) ; } else if (window.attachEvent){ document.getElementById('parent').attachEvent("onmouseout",onMouseOut) ; } }.

15voto

Jamie Brown Points 413

Si vous utilisez jQuery, vous pouvez également utiliser la fonction "mouseleave", qui s'occupe de tout cela pour vous.

$('#thetargetdiv').mouseenter(do_something);
$('#thetargetdiv').mouseleave(do_something_else);

do_something se déclenche lorsque la souris entre dans la division cible ou l'un de ses enfants, do_something_else se déclenche uniquement lorsque la souris quitte la division cible et l'un de ses enfants.

14voto

Lawrence Mok Points 1249

Merci à Amjad Masad qui m'a inspiré.

J'ai la solution suivante qui semble fonctionner dans IE9, FF et Chrome et le code est assez court (sans les choses complexes de fermeture et d'enfant transversal) :

    DIV.onmouseout=function(e){
        // check and loop relatedTarget.parentNode
        // ignore event triggered mouse overing any child element or leaving itself
        var obj=e.relatedTarget;
        while(obj!=null){
            if(obj==this){
                return;
            }
            obj=obj.parentNode;
        }
        // now perform the actual action you want to do only when mouse is leaving the DIV
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X