Comment puis-je détecter lorsque la souris quitte la fenêtre?


102

Je veux pouvoir détecter le moment où la souris quitte la fenêtre afin que je puisse arrêter le déclenchement des événements alors que la souris de l'utilisateur est ailleurs.

Des idées sur la façon de procéder?


1
Découvrez cette bibliothèque github d'intention d'exit d'apiculteur. C'est bien. github.com/beeker1121/exit-intent-popup
raksheetbhat

Utilisez mouseleave pour empêcher le déclenchement sur tous les éléments comme le fait le mouseout : Très bonne explication et support: developer.mozilla.org/en-US/docs/Web/API/Element

Définissez l'événement sur le document - et non sur document.body pour éviter un incendie sur la barre de défilement. La barre de défilement de Windows semble réduire le corps.

Réponses:


100

Gardez à l'esprit que ma réponse a beaucoup vieilli.

Ce type de comportement est généralement souhaité lors de l'implémentation du comportement glisser-déposer sur une page html. La solution ci-dessous a été testée sur IE 8.0.6, FireFox 3.6.6, Opera 10.53 et Safari 4 sur une machine MS Windows XP.
D'abord une petite fonction de Peter-Paul Koch; gestionnaire d'événements cross browser:

function addEvent(obj, evt, fn) {
    if (obj.addEventListener) {
        obj.addEventListener(evt, fn, false);
    }
    else if (obj.attachEvent) {
        obj.attachEvent("on" + evt, fn);
    }
}

Et puis utilisez cette méthode pour attacher un gestionnaire d'événements à l'événement mouseout des objets de document:

addEvent(document, "mouseout", function(e) {
    e = e ? e : window.event;
    var from = e.relatedTarget || e.toElement;
    if (!from || from.nodeName == "HTML") {
        // stop your drag event here
        // for now we can just use an alert
        alert("left window");
    }
});

Enfin, voici une page html avec le script intégré pour le débogage:

<html>
<head>
<script type="text/javascript">
function addEvent(obj, evt, fn) {
    if (obj.addEventListener) {
        obj.addEventListener(evt, fn, false);
    }
    else if (obj.attachEvent) {
        obj.attachEvent("on" + evt, fn);
    }
}
addEvent(window,"load",function(e) {
    addEvent(document, "mouseout", function(e) {
        e = e ? e : window.event;
        var from = e.relatedTarget || e.toElement;
        if (!from || from.nodeName == "HTML") {
            // stop your drag event here
            // for now we can just use an alert
            alert("left window");
        }
    });
});
</script>
</head>
<body></body>
</html>

L'utilisation de window.event a résolu mon problème pour obtenir cet événement. Merci!
Jay

il semble que cela ne se déclenche pas lorsque la souris n'est pas enfoncée dans chrome. il se déclenche lorsque la souris est enfoncée dans le chrome. semble être un comportement incohérent.
antony.trupe

5
Cela ne fonctionne pas si d'autres éléments HTML remplissent la fenêtre.
Emmanuel

Le problème avec cette solution est qu'elle alerte la fenêtre gauche même si l'utilisateur essaie simplement d'utiliser le défilement. J'ai publié une solution à ce problème ici , mais il reste encore un problème à résoudre (voir le lien).
JohnyFree du

1
Utilisez mouseleave au lieu de mouseout pour empêcher le déclenchement des éléments du document. Très bonne explication et cela fonctionne sur IE5.5 ... developer.mozilla.org/en-US/docs/Web/API/Element/…

42

Si vous utilisez jQuery, que diriez-vous de ce code court et doux -

$(document).mouseleave(function () {
    console.log('out');
});

Cet événement se déclenchera chaque fois que la souris n'est pas dans votre page comme vous le souhaitez. Changez simplement la fonction pour faire ce que vous voulez.

Et vous pouvez également utiliser:

$(document).mouseenter(function () {
    console.log('in');
});

À déclencher lorsque la souris revient à la page.

Source: https://stackoverflow.com/a/16029966/895724


mouseleave fonctionne mais il déclenche également si l'inspection de l'élément est ouverte, comment l'empêcher? Idée?
Pankaj Verma

Cette technique n'est pas stable dans Chrome 15 à 56 (ma version actuelle). Mais cela fonctionne très bien dans Firefox. Voir: stackoverflow.com/questions/7448468/…
Tremours

mouseleave semble tirer beaucoup plus qu'il ne le devrait.
Alexander

Il se déclenche également si la fenêtre est en arrière-plan (navigateur non focalisé) et que la souris entre dans la fenêtre (Chrome 61 / macOS10.11)
CodeBrauer

1
@Skeets (et futurs lecteurs) Ce problème a été marqué comme résolu le 14 février 2019
Xandor

27

Cela fonctionne pour moi:

addEvent(document, 'mouseout', function(evt) {
  if (evt.toElement == null && evt.relatedTarget == null) {
    alert("left window");
  }
});

9
Qu'est-ce que c'est addEvent?
Yi Jiang

5
c'est une fonction définie dans la réponse de Joshua Mills
superjos

4
sur ie8, relatedTarget n'est pas défini, sur ie9 + et firefox, toElement n'est pas défini. Parce que cela, l'évaluation correcte est: if ((evt.relatedTarget === null) || (evt.toElement === null)) {
carlos

1
Le prédicat pourrait être plus concis que dansif (!evt.toElement && !evt.relatedTarget)
Pavel Ye

20

Afin de détecter la sortie de la souris sans prendre en compte la barre de défilement et le champ autcomplete ou inspecter:

document.addEventListener("mouseleave", function(event){

  if(event.clientY <= 0 || event.clientX <= 0 || (event.clientX >= window.innerWidth || event.clientY >= window.innerHeight))
  {

     console.log("I'm out");

  }
});

Explications des conditions:

event.clientY <= 0  is when the mouse leave from the top
event.clientX <= 0  is when the mouse leave from the left
event.clientX >= window.innerWidth is when the mouse leave from the right
event.clientY >= window.innerHeight is when the mouse leave from the bottom

========================= EDIT ========================== ======

document.addEventListener ("mouseleave") ne semble pas être déclenché sur la nouvelle version de Firefox, mouseleave doit être attaché à un élément comme body, ou à un élément enfant.

Je suggère d'utiliser à la place

document.body.addEventListener("mouseleave")

Ou

window.addEventListener("mouseout")

de temps en temps pas tiré. Les coutures échouent lorsqu'un point de flux de points déclenché par le déplacement du curseur vise la bordure et le curseur devient redimensionné.
Ivan Borshchov

@ user3479125, pourriez-vous l'essayer également sur mon extrait de code et voir si le problème persiste lorsque l'instruction if n'est pas ajoutée? Il prend en compte la barre de défilement mais je n'ai pas testé avec autocomplete ou inspecter. stackoverflow.com/a/56678357/985399

7

L'utilisation de l'événement onMouseLeave empêche la formation de bulles et vous permet de détecter facilement le moment où la souris quitte la fenêtre du navigateur.

<html onmouseleave="alert('You left!')"></html>

http://www.w3schools.com/jsref/event_onmouseleave.asp


Fantastique! Le support est IE5.5 + ... Fonctionne aussi: document.onmouseleave = function() { alert('You left!') };utilisez not document.body qui déclenche des barres de défilement qui rétrécissent le corps! Le code pour empêcher le feu sur les éléments n'est pas nécessaire. Bonne explication: developer.mozilla.org/en-US/docs/Web/API/Element/…

6

Aucune de ces réponses n'a fonctionné pour moi. J'utilise maintenant:

document.addEventListener('dragleave', function(e){

    var top = e.pageY;
    var right = document.body.clientWidth - e.pageX;
    var bottom = document.body.clientHeight - e.pageY;
    var left = e.pageX;

    if(top < 10 || right < 20 || bottom < 10 || left < 10){
        console.log('Mouse has moved out of window');
    }

});

J'utilise ceci pour un widget de téléchargement de fichiers par glisser-déposer. Ce n'est pas absolument précis, étant déclenché lorsque la souris arrive à une certaine distance du bord de la fenêtre.


Je crois que cela ne se déclenchera parfois pas si le mouvement de la souris est "assez rapide".
John Weisz

@JohnWeisz Oui, je pense que vous avez raison. J'utilise ce script depuis un moment maintenant et cela fonctionne bien.
Emmanuel

6

J'ai essayé tout ce qui précède, mais rien ne semble fonctionner comme prévu. Après quelques recherches, j'ai trouvé que e.relatedTarget est le code HTML juste avant que la souris ne quitte la fenêtre .

Alors ... j'ai fini avec ceci:


document.body.addEventListener('mouseout', function(e) {
    if (e.relatedTarget === document.querySelector('html')) {
        console.log('We\'re OUT !');
    }
});

Faites-moi savoir si vous trouvez des problèmes ou des améliorations!

Mise à jour 2019

(comme user1084282 l'a découvert)

document.body.addEventListener('mouseout', function(e) {
    if (!e.relatedTarget && !e.toElement) {
        console.log('We\'re OUT !');
    }
});

2
Ne fonctionne pas pour moi sur Chrome. relatedTargetest nul lorsque la souris quitte la fenêtre. Inspiré par la réponse de @ user1084282, changez-le en ceci: if(!e.relatedTarget && !e.toElement) { ... }et ça marche

Je confirme que cela fonctionne bien sur Chrome, Firefox et IE Edge, si vous utilisez à la if(!e.relatedTarget && !e.toElement)place de la condition dans la réponse réelle. Il détecte que la souris quitte le corps du document.
Haijerome

Ne placez pas l'événement sur document.body car la barre de défilement de Windows peut le réduire et déclencher le défilement. Et pourquoi avez-vous un «mouseout» qui se déclenche sur tous les éléments bouillonnés alors que vous pouvez avoir «mouseleave»? developer.mozilla.org/en-US/docs/Web/API/Element/…

2

Je reprends ce que j'ai dit. C'est possible. J'ai écrit ce code, fonctionne parfaitement.

window.onload = function() {

    $span = document.getElementById('text');

    window.onmouseout = function() {
        $span.innerHTML = "mouse out";  
    }

    window.onmousemove = function() {
        $span.innerHTML = "mouse in";   
    }

}

fonctionne dans chrome, firefox, opéra. Aint testé dans IE mais suppose que cela fonctionne.

Éditer. IE comme toujours cause des problèmes. Pour le faire fonctionner dans IE, remplacez les événements d'une fenêtre à l'autre:

window.onload = function() {

    $span = document.getElementById('text');

    document.onmousemove = function() {
        $span.innerHTML = "mouse move";
    }

    document.onmouseout = function() {
        $span.innerHTML = "mouse out";
    }

}

combinez-les pour la détection de curseur crossbrowser kick ass o0: P


Avez-vous testé à quel point cela fonctionne avec les éléments de la page? Je pense que les éléments qui ont leurs propres événements «onmouseover / out» pourraient potentiellement annuler le bouillonnement et casser cette fonctionnalité.
Dan Herbert

1
Ozzy, Dan essaie d'expliquer qu'un élément qui arrête la propagation de l'événement empêchera l'événement d'atteindre le document / la fenêtre, rendant ainsi votre solution inefficace.
James

Je viens de le tester avec d'autres éléments avec leurs propres événements onmousemove et onmouseout et cela fonctionne toujours bien.
Ozzy

2
Oui, d'accord, mais encore une fois, nous parlons de propagation d'événements. Si vous arrêtez délibérément la propagation d'événements avec EVENT.stopPropagation () (pour IE, EVENT.cancelBubble = true), cela ne montera pas dans le document / la fenêtre ... Pour contrer cela, vous pouvez utiliser la capture d'événements dans les navigateurs qui la prennent en charge .
James

N'oubliez pas que dans JS pour déclarer une variable, vous devez utiliser «var». Maintenant, la variable $ span est un global implicite, ce qui n'est probablement pas ce que vous voulez. Au cas où ce ne serait pas intentionnel, vous n'avez pas besoin d'un $ dans les noms de variables.
Jani Hartikainen

2

appliquez ce css:

html
{
height:100%;
}

Cela garantit que l'élément html occupe toute la hauteur de la fenêtre.

appliquez cette jquery:

$("html").mouseleave(function(){
 alert('mouse out');
});

Le problème avec mouseover et mouseout est que si vous survolez / sortez du html vers un élément enfant, cela déclenchera l'événement. La fonction que j'ai donnée n'est pas activée lorsque vous passez la souris sur un élément enfant. Il ne se déclenche que lorsque vous sortez / rentrez la souris de la fenêtre

juste pour que vous sachiez que vous pouvez le faire lorsque l'utilisateur souris dans la fenêtre:

$("html").mouseenter(function(){
  alert('mouse enter');
});

2
Par "Je ne crois pas que javascript a une fonction équivalente", vous voulez dire, vous ne savez pas que jQuery EST une bibliothèque de fonctions javascript et que jQuery EST écrit AVEC et POUR javascript?
Milche Patern

2
@MilchePatern J'ai écrit cette réponse il y a presque deux ans. J'étais plus ignorant à l'époque et je ne réalisais pas que tout ce qui est fait dans jQuery peut être fait en JavaScript pur. Je
mettrai à

2

J'ai essayé les uns après les autres et j'ai trouvé la meilleure réponse à l'époque:

https://stackoverflow.com/a/3187524/985399

J'ai ignoré les anciens navigateurs, j'ai donc raccourci le code pour qu'il fonctionne sur les navigateurs modernes (IE9 +)

    document.addEventListener("mouseout", function(e) {
        let t = e.relatedTarget || e.toElement;
        if (!t || t.nodeName == "HTML") {
          console.log("left window");
        }
    });

document.write("<br><br>PROBLEM<br><br><div>Mouseout trigg on HTML elements</div>")

Ici vous voyez le support du navigateur

C'était assez court je pensais

Mais un problème subsistait car "mouseout" se déclenchait sur tous les éléments du document .

Pour éviter que cela ne se produise, utilisez mouseleave (IE5.5 +). Voir la bonne explication dans le lien.

Le code suivant fonctionne sans déclencher sur les éléments à l'intérieur de l'élément à l'intérieur ou à l'extérieur de. Essayez également de glisser-relâcher en dehors du document.

var x = 0

document.addEventListener("mouseleave", function(e) { console.log(x++) 
})

document.write("<br><br>SOLUTION<br><br><div>Mouseleave do not trigg on HTML elements</div>")

Vous pouvez définir l'événement sur n'importe quel élément HTML. N'activez pas l'événement document.body, car la barre de défilement de Windows peut réduire le corps et se déclencher lorsque le pointeur de la souris est au-dessus de la barre de défilement lorsque vous souhaitez faire défiler mais pas déclencher un événement mouseLeave dessus. Activez-le à la documentplace, comme dans l'exemple.


1

Peut-être que si vous écoutez constamment OnMouseOver dans la balise body, puis rappelez-vous lorsque l'événement ne se produit pas, mais, comme Zack le déclare, cela pourrait être très moche, car tous les navigateurs ne gèrent pas les événements de la même manière, il y en a même certains. possibilité que vous perdiez le MouseOver même en étant sur un div dans la même page.


Ce n'est pas une réponse

1

Peut-être que cela aiderait certains de ceux qui viennent ici plus tard. window.onbluret document.mouseout.

window.onblur est déclenché lorsque:

  • Vous passez à une autre fenêtre en utilisant Ctrl+Tabou Cmd+Tab.
  • Vous vous concentrez (pas seulement au passage de la souris) sur l'inspecteur de document.
  • Vous changez de bureau.

Fondamentalement, chaque fois que l'onglet du navigateur perd le focus.

window.onblur = function(){
    console.log("Focus Out!")
}

document.mouseout est déclenché lorsque:

  • Vous déplacez le curseur sur la barre de titre.
  • Vous passez à une autre fenêtre en utilisant Ctrl+Tabou Cmd+Tab.
  • Vous ouvrez déplacer le curseur sur l'inspecteur de document.

En gros dans tous les cas lorsque votre curseur quitte le document.

document.onmouseleave = function(){
    console.log("Mouse Out!")
}

"asically chaque fois que l'onglet du navigateur perd le focus." .. avec les anciennes versions d'IE, l'événement 'blur' est compilé par DOM quand / après qu'un autre élément reçoit le focus, pour gooChrome, c'est quand l'élément lui-même perd le focus .. juste pour le mentionner.
Milche Patern

Utilisation intelligente window.onbluraussi. +1
Programmes Redwolf

1
$(window).mouseleave(function(event) {
  if (event.toElement == null) {
    //Do something
  }
})

Cela peut être un peu piraté mais cela ne se déclenchera que lorsque la souris quittera la fenêtre. J'ai continué à attraper des événements d'enfants et cela l'a résolu



1

Cela a fonctionné pour moi. Une combinaison de certaines des réponses ici. Et j'ai inclus le code montrant un modèle une seule fois. Et le modèle disparaît lorsque vous cliquez ailleurs.

<script>
    var leave = 0
    //show modal when mouse off of page
    $("html").mouseleave(function() {
       //check for first time
       if (leave < 1) {
          modal.style.display = "block";
          leave = leave + 1;
       }
    });

    // Get the modal with id="id01"
       var modal = document.getElementById('id01');

    // When the user clicks anywhere outside of the modal, close it
       window.onclick = function(event) {
          if (event.target == modal) {
             modal.style.display = "none";
          }
       }
</script>

Il n'y avait aucune balise jQuery sur la question
mrReiha

jQuery est beaucoup de code par rapport à ma réponse qui fonctionne sur les navigateurs modernes IE9 + et le reste. Il est basé sur cette réponse mais beaucoup plus courte: stackoverflow.com/a/3187524/985399

1

Voir mouseoveret mouseout.

var demo = document.getElementById('demo');
document.addEventListener("mouseout", function(e){demo.innerHTML="😞";});
document.addEventListener("mouseover", function(e){demo.innerHTML="😊";});
div { font-size:80vmin; position:absolute;
      left:50%; top:50%; transform:translate(-50%,-50%); }
<div id='demo'>😐</div>


0

Je n'ai pas testé cela, mais mon instinct serait de faire un appel de fonction OnMouseOut sur la balise body.


-2

Cela fonctionnera dans Chrome,

$(document).bind('dragleave', function (e) {
    if (e.originalEvent.clientX == 0){
        alert("left window");
    }
});
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.