¿Cómo puedo detectar cuando el ratón sale de la ventana?

102

Quiero poder detectar cuándo el mouse sale de la ventana para poder evitar que los eventos se activen mientras el mouse del usuario está en otro lugar.

¿Alguna idea de cómo hacer esto?


fuente
1
Echa un vistazo a esta biblioteca de github con intención de salida de beeker. Es genial. github.com/beeker1121/exit-intent-popup
raksheetbhat
Use mouseleave para evitar disparar en todos los elementos como lo hace el mouseout : Muy buena explicación y soporte: developer.mozilla.org/en-US/docs/Web/API/Element/…
Configure el evento en el documento, no en el cuerpo del documento para evitar que se active la barra de desplazamiento. La barra de desplazamiento de Windows parece encoger el cuerpo.

Respuestas:

100

Tenga en cuenta que mi respuesta ha envejecido mucho.

Este tipo de comportamiento generalmente se desea al implementar el comportamiento de arrastrar y soltar en una página html. La siguiente solución se probó en IE 8.0.6, FireFox 3.6.6, Opera 10.53 y Safari 4 en una máquina con MS Windows XP.
Primero una pequeña función de Peter-Paul Koch; controlador de eventos de navegador cruzado:

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

Y luego use este método para adjuntar un controlador de eventos al evento mouseout de objetos de documento:

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

Finalmente, aquí hay una página html con el script incrustado para la depuración:

<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>
J Mills
fuente
El uso de window.event solucionó mi problema al obtener este evento. ¡Gracias!
Jay
parece que esto no se dispara cuando el mouse no está presionado en Chrome. se dispara cuando se presiona el mouse en cromo. parece un comportamiento inconsistente.
antony.trupe
5
Esto no funciona si otros elementos HTML están llenando la ventana.
Emmanuel
El problema con esta solución es que alerta a la ventana izquierda incluso si el usuario intenta usar el desplazador. Publiqué la solución a este problema aquí , pero todavía hay un problema que debe resolverse (ver el enlace).
JohnyFree
1
Utilice mouseleave en lugar de mouseout para evitar disparar elementos en el documento. Muy buena explicación y funciona en IE5.5 ... developer.mozilla.org/en-US/docs/Web/API/Element/…
42

Si está utilizando jQuery, ¿qué tal este código corto y dulce?

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

Este evento se activará siempre que el mouse no esté en su página como lo desea. Simplemente cambie la función para hacer lo que quiera.

Y también podrías usar:

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

Para disparar cuando el mouse entra de nuevo a la página.

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

Mandeep Janjua
fuente
mouseleave está funcionando pero también se dispara si el elemento de inspección está abierto, ¿cómo prevenirlo? ¿Idea?
Pankaj Verma
Esta técnica no es estable en Chrome 15 a 56 (mi versión actual). Pero funciona muy bien en Firefox. Ver: stackoverflow.com/questions/7448468/…
Tremours
mouseleave parece disparar mucho más de lo que debería.
Alexander
También se activa si la ventana está en segundo plano (el navegador no está enfocado) y el mouse ingresa a la ventana (Chrome 61 / macOS10.11)
CodeBrauer
1
@Skeets (y futuros lectores) Este problema se marcó como corregido a partir del 14 de febrero de 2019
Xandor
27

Esto funciona para mi:

addEvent(document, 'mouseout', function(evt) {
  if (evt.toElement == null && evt.relatedTarget == null) {
    alert("left window");
  }
});
usuario1084282
fuente
9
¿Qué es addEvent?
Yi Jiang
5
es una función definida en la respuesta de Joshua Mills
superjos
4
en ie8, relatedTarget no está definido, en ie9 + y firefox, toElement no está definido. Por eso, la evaluación correcta es: if ((evt.relatedTarget === null) || (evt.toElement === null)) {
carlos
1
El predicado podría ser más conciso como enif (!evt.toElement && !evt.relatedTarget)
Pavel Ye
20

Para detectar la salida del mouse sin tener en cuenta la barra de desplazamiento y el campo de autocompletar o inspeccionar:

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

  }
});

Explicaciones de condiciones:

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

======================== EDITAR ========================= ======

document.addEventListener ("mouseleave") parece no activarse en la nueva versión de Firefox, mouseleave debe adjuntarse a un elemento como body o un elemento secundario.

Sugiero usar en su lugar

document.body.addEventListener("mouseleave")

O

window.addEventListener("mouseout")
Daphoque
fuente
de vez en cuando no se dispara. Parece que falla cuando un punto de la corriente de puntos se activa por el cursor que mueve el borde del objetivo y el cursor cambia de tamaño.
Ivan Borshchov
@ user3479125, ¿podría probarlo también en mi fragmento y ver si el problema persiste cuando no se agrega la instrucción if? Tiene en cuenta la barra de desplazamiento pero no la he probado con autocompletar o inspeccionar. stackoverflow.com/a/56678357/985399
7

El uso del evento onMouseLeave evita el burbujeo y le permite detectar fácilmente cuando el mouse sale de la ventana del navegador.

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

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

Samy Bencherif
fuente
¡Fantástico! El soporte es IE5.5 + ... Funciona también: ¡ document.onmouseleave = function() { alert('You left!') };No use document.body que dispara barras de desplazamiento que encogen el cuerpo! No se necesita código para prevenir incendios en los elementos. Buena explicación: developer.mozilla.org/en-US/docs/Web/API/Element/…
6

Ninguna de estas respuestas funcionó para mí. Ahora estoy usando:

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

});

Estoy usando esto para un widget de carga de archivos de arrastrar y soltar. No es absolutamente exacto, se activa cuando el mouse llega a una cierta distancia del borde de la ventana.

Emmanuel
fuente
Creo que esto a veces no se activará si el movimiento del mouse es "lo suficientemente rápido".
John Weisz
@JohnWeisz Sí, creo que tienes razón. He usado este script por un tiempo y funciona bien.
Emmanuel
6

He intentado todo lo anterior, pero nada parece funcionar como se esperaba. Después de investigar un poco, descubrí que e.relatedTarget es el html justo antes de que el mouse salga de la ventana .

Entonces ... terminé con esto:


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

Por favor, avíseme si encuentra algún problema o mejora.

Actualización 2019

(como descubrió el usuario1084282)

document.body.addEventListener('mouseout', function(e) {
    if (!e.relatedTarget && !e.toElement) {
        console.log('We\'re OUT !');
    }
});
Claudiu
fuente
2
No me funciona en Chrome. relatedTargetes nulo cuando el mouse sale de la ventana. Inspirado por la respuesta de @ user1084282, cámbielo a esto: if(!e.relatedTarget && !e.toElement) { ... }y funciona
Confirmo que esto funciona bien en Chrome, Firefox e IE Edge, si usa en if(!e.relatedTarget && !e.toElement)lugar de la condición en la respuesta real. Detecta que el ratón abandona el cuerpo del documento.
Haijerome
No tenga el evento en document.body porque la barra de desplazamiento de Windows puede encogerlo y disparar sobre el desplazamiento. ¿Y por qué tiene 'mouseout' que se activa en todos los elementos burbujeados cuando puede tener 'mouseleave'? developer.mozilla.org/en-US/docs/Web/API/Element/…
2

Retiro lo que dije. Es posible. Escribí este código, funciona perfectamente.

window.onload = function() {

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

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

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

}

funciona en chrome, firefox, opera. No se ha probado en IE, pero se supone que funciona.

editar. IE como siempre causa problemas. Para que funcione en IE, reemplace los eventos de la ventana al documento:

window.onload = function() {

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

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

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

}

combinarlos para la detección del cursor del navegador cruzado o0: P

Ozzy
fuente
¿Ha probado qué tan bien funciona esto junto con los elementos de la página? Creo que los elementos que tienen sus propios eventos 'onmouseover / out' podrían cancelar el burbujeo y romper esta funcionalidad.
Dan Herbert
1
Ozzy, Dan está tratando de explicar que un elemento que detiene la propagación de eventos evitará que el evento llegue al documento / ventana, haciendo que su solución sea ineficaz.
James
Lo probé con otros elementos con sus propios eventos onmousemove y onmouseout y todavía funciona bien.
Ozzy
2
Sí, está bien, pero de nuevo estamos hablando de propagación de eventos. Si detiene intencionalmente la propagación de eventos con EVENT.stopPropagation () (para IE, EVENT.cancelBubble = true), entonces no aparecerá en el documento / ventana ... Para contrarrestar esto, puede usar la captura de eventos en navegadores que lo admitan .
James
Recuerde que en JS para declarar una variable, debe usar 'var'. Ahora, la variable $ span es un global implícito, que probablemente no sea lo que desea. Además, en caso de que no sea intencional, no necesita un $ en los nombres de las variables.
Jani Hartikainen
2

aplicar este CSS:

html
{
height:100%;
}

Esto asegura que el elemento html ocupa toda la altura de la ventana.

aplicar este jquery:

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

El problema con el mouseover y mouseout es que si pasa el mouse sobre / fuera de html a un elemento secundario, se activará el evento. La función que di no se activa al pasar el mouse a un elemento secundario. Solo se activa cuando coloca el mouse fuera / dentro de la ventana

solo para que sepas que puedes hacerlo cuando el usuario pase el mouse por la ventana:

$("html").mouseenter(function(){
  alert('mouse enter');
});
www139
fuente
2
Por "No creo que javascript tenga una función equivalente", quieres decir, ¿no sabes que jQuery ES una biblioteca de funciones de javascript y que jQuery ESTÁ escrito CON y PARA javascript?
Milche Patern
2
@MilchePatern Escribí esta respuesta hace casi dos años. En ese entonces era más ignorante y no me di cuenta del hecho de que cualquier cosa que se haga en jQuery se puede hacer en JavaScript puro. Actualizaré la respuesta ...
www139
2

Probé uno tras otro y encontré la mejor respuesta en ese momento:

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

Omití los navegadores antiguos, así que reduje el código para que funcione en navegadores modernos (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>")

Aquí ves el soporte del navegador

Eso fue bastante corto, pensé

Pero el problema persiste porque "mouseout" se activa en todos los elementos del documento .

Para evitar que suceda, use mouseleave (IE5.5 +). Vea la buena explicación en el enlace.

El siguiente código funciona sin activar elementos dentro del elemento para estar dentro o fuera de. Intente también arrastrar y soltar fuera del documento.

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>")

Puede configurar el evento en cualquier elemento HTML. Sin document.bodyembargo, no tenga el evento activado, porque la barra de desplazamiento de Windows puede encoger el cuerpo y dispararse cuando el puntero del mouse está sobre la barra de desplazamiento cuando desea desplazarse pero no desea activar un evento mouseLeave sobre él. Actívelo en su documentlugar, como en el ejemplo.


fuente
1

Tal vez si está escuchando constantemente OnMouseOver en la etiqueta del cuerpo, entonces devuelva la llamada cuando el evento no esté ocurriendo, pero, como dice Zack, esto podría ser muy feo, porque no todos los navegadores manejan los eventos de la misma manera, incluso hay algunos posibilidad de que pierda MouseOver incluso al estar sobre un div en la misma página.

Pablo Albornoz
fuente
No es una respuesta
1

Quizás esto ayude a algunos de los que vendrán aquí más tarde. window.onblury document.mouseout.

window.onblur se activa cuando:

  • Cambia a otra ventana usando Ctrl+Tabo Cmd+Tab.
  • Usted se enfoca (no solo con el mouse) en el inspector de documentos.
  • Cambias de escritorio.

Básicamente, cada vez que la pestaña del navegador pierde el foco.

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

document.mouseout se activa cuando:

  • Mueves el cursor a la barra de título.
  • Cambia a otra ventana usando Ctrl+Tabo Cmd+Tab.
  • Abre mover el cursor sobre el inspector de documentos.

Básicamente, en cualquier caso, cuando el cursor abandona el documento.

document.onmouseleave = function(){
    console.log("Mouse Out!")
}
Jayant Bhawal
fuente
"asicamente cada vez que la pestaña del navegador pierde el foco". .. con versiones anteriores de IE, el evento 'desenfoque' es DOM compuesto cuando / después de que otro elemento recibe el foco, para gooChrome, es cuando el elemento en sí pierde el foco .. solo por mencionar.
Milche Patern
Uso inteligente window.onblurtambién. +1
Programas Redwolf
1
$(window).mouseleave(function(event) {
  if (event.toElement == null) {
    //Do something
  }
})

Esto puede ser un poco complicado, pero solo se activará cuando el mouse abandone la ventana. Seguí captando eventos infantiles y esto lo resolvió

Cekaleek
fuente
1
$(window).mouseleave(function() {
 alert('mouse leave');
});
sandeep kumar
fuente
1

Esto funcionó para mí. Una combinación de algunas de las respuestas aquí. E incluí el código que muestra un modelo solo una vez. Y el modelo desaparece cuando se hace clic en cualquier otro lugar.

<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>
Morgan Hayes
fuente
No había ninguna etiqueta jQuery en la pregunta
mrReiha
jQuery es mucho código en comparación con mi respuesta que funciona en los navegadores modernos IE9 + y el resto. Se basa en esta respuesta, pero es mucho más corta: stackoverflow.com/a/3187524/985399
1

Ver mouseovery 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>

Ashleedawg
fuente
0

No he probado esto, pero mi instinto sería hacer una llamada a la función OnMouseOut en la etiqueta del cuerpo.

Ender
fuente
-2

Esto funcionará en Chrome,

$(document).bind('dragleave', function (e) {
    if (e.originalEvent.clientX == 0){
        alert("left window");
    }
});
anupraj
fuente