Jak mogę wykryć, że mysz opuszcza okno?

102

Chcę mieć możliwość wykrywania, kiedy mysz opuszcza okno, aby móc zatrzymać uruchamianie zdarzeń, gdy mysz użytkownika znajduje się w innym miejscu.

Jakieś pomysły, jak to zrobić?


źródło
1
Sprawdź tę bibliotekę Github Beeker z zamiarami wyjścia. Wspaniale. github.com/beeker1121/exit-intent-popup
raksheetbhat
Użyj mouseleave, aby zapobiec odpalaniu wszystkich elementów, tak jak robi to myszka : Bardzo dobre wyjaśnienie i wsparcie: developer.mozilla.org/en-US/docs/Web/API/Element/ ...
Ustaw zdarzenie w dokumencie - nie document.body, aby zapobiec pożarowi powyżej paska przewijania. Pasek przewijania systemu Windows wydaje się zmniejszać ciało.

Odpowiedzi:

100

Pamiętaj, że moja odpowiedź bardzo się postarzała.

Ten typ zachowania jest zwykle pożądany podczas implementowania zachowania przeciągnij-upuść na stronie html. Poniższe rozwiązanie zostało przetestowane w przeglądarkach IE 8.0.6, FireFox 3.6.6, Opera 10.53 i Safari 4 na komputerze z systemem MS Windows XP.
Najpierw mała funkcja od Petera-Paula Kocha; obsługa zdarzeń w różnych przeglądarkach:

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

Następnie użyj tej metody, aby dołączyć procedurę obsługi zdarzenia do zdarzenia mouseout obiektów dokumentu:

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

Wreszcie, oto strona HTML ze skryptem osadzonym do debugowania:

<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
źródło
Korzystanie z window.event rozwiązało mój problem z pobieraniem tego zdarzenia. Dzięki!
Jay
wygląda na to, że nie uruchamia się, gdy mysz nie jest wciśnięta w chrome. uruchamia się, gdy mysz jest wciśnięta w chrom. wydaje się niespójnym zachowaniem.
antony.trupe
5
To nie działa, jeśli inne elementy HTML wypełniają okno.
Emmanuel
Problem z tym rozwiązaniem polega na tym, że ostrzega lewe okno, nawet jeśli użytkownik po prostu próbuje użyć scrollera. Tutaj opublikowałem rozwiązanie tego problemu , ale jest jeszcze jeden problem do rozwiązania (patrz link).
JohnyFree
1
Użyj mouseleave zamiast myszy, aby zapobiec pożarowi elementów w dokumencie. Bardzo dobre wyjaśnienie i działa na IE5.5 ... developer.mozilla.org/en-US/docs/Web/API/Element/
42

Jeśli używasz jQuery, co powiesz na ten krótki i słodki kod -

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

To zdarzenie będzie wywoływane za każdym razem, gdy na stronie nie ma myszy, tak jak chcesz. Po prostu zmień funkcję, aby robić, co chcesz.

Możesz też użyć:

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

Aby wywołać, gdy mysz ponownie wejdzie na stronę.

Źródło: https://stackoverflow.com/a/16029966/895724

Mandeep Janjua
źródło
mouseleave działa, ale również strzela, jeśli element inspekcji jest otwarty, jak temu zapobiec? Pomysł?
Pankaj Verma
Ta technika nie jest stabilna w Chrome 15 do 56 (moja obecna wersja). Ale działa bardzo dobrze w Firefoksie. Zobacz: stackoverflow.com/questions/7448468/ ...
Tremours
mouseleave wydaje się strzelać dużo więcej niż powinien.
Alexander
Uruchamia się również, jeśli okno jest w tle (przeglądarka nie jest skoncentrowana), a mysz wchodzi do okna (Chrome 61 / macOS10.11)
CodeBrauer
1
@Skeets (i przyszli czytelnicy) Ten problem został oznaczony jako naprawiony od 14 lutego 2019 r.
Xandor
27

To działa dla mnie:

addEvent(document, 'mouseout', function(evt) {
  if (evt.toElement == null && evt.relatedTarget == null) {
    alert("left window");
  }
});
user1084282
źródło
9
Co to jest addEvent?
Yi Jiang,
5
jest to funkcja zdefiniowana w odpowiedzi Joshua Millsa
superjos
4
na ie8 relatedTarget jest niezdefiniowane, na ie9 + i firefox, toElement jest niezdefiniowane. Ponieważ tak, prawidłowa ocena to: if ((evt.relatedTarget === null) || (evt.toElement === null)) {
carlos
1
Predykat mógłby być bardziej zwięzły jak wif (!evt.toElement && !evt.relatedTarget)
Pavel Ye
20

Aby wykryć mouseleave bez uwzględnienia paska przewijania i pola autouzupełniania lub inspekcji:

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

  }
});

Warunki wyjaśnienia:

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

======================== EDYCJA ========================= ======

Document.addEventListener ("mouseleave") wydaje się nie uruchamiać w nowej wersji przeglądarki Firefox, mouseleave musi być dołączone do elementu takiego jak body lub elementu podrzędnego.

Proponuję zamiast tego użyć

document.body.addEventListener("mouseleave")

Lub

window.addEventListener("mouseout")
Daphoque
źródło
od czasu do czasu nie wystrzelił. Wygląda na to, że zawodzi, gdy strumień jednego punktu jest wyzwalany przez przesuwanie kursora, a jego rozmiar zmienia się.
Ivan Borshchov
@ user3479125, czy możesz wypróbować to również na moim fragmencie i sprawdzić, czy problem nadal występuje, gdy instrukcja if nie zostanie dodana? Uwzględnia pasek przewijania, ale nie testowałem z autouzupełnianiem ani inspekcją. stackoverflow.com/a/56678357/985399
7

Użycie zdarzenia onMouseLeave zapobiega bulgotaniu i pozwala łatwo wykryć, kiedy mysz opuszcza okno przeglądarki.

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

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

Samy Bencherif
źródło
Fantastyczny! Obsługiwane jest IE5.5 + ... Działa również: document.onmouseleave = function() { alert('You left!') };nie używaj document.body, który odpala powyżej pasków przewijania, które zmniejszają ciało! Kod zapobiegający pożarowi elementów nie jest potrzebny. Dobre wyjaśnienie: developer.mozilla.org/en-US/docs/Web/API/Element/ ...
6

Żadna z tych odpowiedzi nie zadziałała dla mnie. Teraz używam:

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

});

Używam tego do przeciągania i upuszczania widżetu do przesyłania plików. Nie jest to całkowicie dokładne, ponieważ jest uruchamiane, gdy mysz znajdzie się w pewnej odległości od krawędzi okna.

Emmanuel
źródło
Uważam, że czasami się to nie uruchamia, jeśli ruch myszy jest „wystarczająco szybki”.
John Weisz
@JohnWeisz Tak, myślę, że masz rację. Używam tego skryptu od jakiegoś czasu i działa dobrze.
Emmanuel
6

Wypróbowałem wszystkie powyższe, ale nic nie działa zgodnie z oczekiwaniami. Po krótkich poszukiwaniach odkryłem, że e.relatedTarget to kod HTML tuż przed wyjściem myszy z okna .

Więc ... Skończyło się na tym:


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

Daj mi znać, jeśli znajdziesz jakieś problemy lub ulepszenia!

Aktualizacja 2019

(jak dowiedział się użytkownik1084282)

document.body.addEventListener('mouseout', function(e) {
    if (!e.relatedTarget && !e.toElement) {
        console.log('We\'re OUT !');
    }
});
Claudiu
źródło
2
Nie działa dla mnie na chrome. relatedTargetjest zerowa, gdy mysz opuszcza okno. Zainspirowany odpowiedzią @ user1084282, zmień to na to: if(!e.relatedTarget && !e.toElement) { ... }i działa
Potwierdzam, że działa to dobrze w Chrome, Firefox i IE Edge, jeśli użyjesz if(!e.relatedTarget && !e.toElement)zamiast warunku w rzeczywistej odpowiedzi. Wykrywa, że ​​mysz opuszcza treść dokumentu.
Haijerome
Nie umieszczaj zdarzenia w pliku document.body, ponieważ pasek przewijania systemu Windows może je zmniejszyć i uruchomić nad zwojem. I dlaczego masz „mouseout”, który uruchamia się na wszystkich bąbelkowych elementach, skoro możesz mieć „mouseleave”? developer.mozilla.org/en-US/docs/Web/API/Element/ ...
2

Cofam to, co powiedziałem. To jest możliwe. Napisałem ten kod, działa idealnie.

window.onload = function() {

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

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

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

}

działa w chrome, firefox, opera. Nie testowano w IE, ale załóżmy, że działa.

edytować. IE jak zawsze sprawia kłopoty. Aby to działało w IE, zamień zdarzenia z okna na dokument:

window.onload = function() {

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

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

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

}

połącz je, aby wykryć kursor wykopu między przeglądarkami o0: P

Ozzy
źródło
Czy przetestowałeś, jak dobrze to działa razem z elementami na stronie? Wydaje mi się, że elementy, które mają własne zdarzenia „onmouseover / out”, mogą potencjalnie anulować bulgotanie i złamać tę funkcjonalność.
Dan Herbert
1
Ozzy, Dan próbuje wyjaśnić, że element, który zatrzymuje propagację zdarzenia, uniemożliwi jego dotarcie do dokumentu / okna, przez co twoje rozwiązanie będzie nieskuteczne.
James
Właśnie przetestowałem to z innymi elementami z własnymi zdarzeniami onmousemove i onmouseout i nadal działa dobrze.
Ozzy
2
Tak, dobrze, ale znowu mówimy o propagowaniu wydarzeń. Jeśli celowo zatrzymasz propagację zdarzeń za pomocą EVENT.stopPropagation () (dla IE, EVENT.cancelBubble = true), to nie pojawi się ona w dokumencie / oknie ... Aby temu przeciwdziałać, możesz użyć przechwytywania zdarzeń w przeglądarkach, które je obsługują .
James
Pamiętaj, że w JS, aby zadeklarować zmienną, musisz użyć 'var'. Teraz zmienna $ span jest niejawną globalną, co prawdopodobnie nie jest tym, czego chcesz. Jeśli nie jest to zamierzone, nie potrzebujesz znaku $ w nazwach zmiennych.
Jani Hartikainen
2

zastosuj ten CSS:

html
{
height:100%;
}

Dzięki temu element html zajmie całą wysokość okna.

zastosuj to jquery:

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

Problem z najechaniem myszą i wyprowadzeniem myszy polega na tym, że jeśli przesuniesz kursor myszy na element podrzędny lub najedziesz kursorem na element podrzędny, spowoduje to wyzwolenie zdarzenia. Funkcja, którą podałem, nie jest włączana po najechaniu myszą na element potomny. Jest wyłączany tylko po najechaniu kursorem myszy na okno

tylko po to, żebyś wiedział, że możesz to zrobić, gdy użytkownik najedzie myszką w oknie:

$("html").mouseenter(function(){
  alert('mouse enter');
});
www139
źródło
2
Mówiąc „Nie wierzę, że javascript ma równoważną funkcję”, masz na myśli, że nie wiesz, że jQuery JEST biblioteką funkcji javascript i że jQuery JEST napisane Z i DLA javascript?
Milche Patern,
2
@MilchePatern Napisałem tę odpowiedź prawie dwa lata temu. Byłem wtedy bardziej ignorantem i nie zdawałem sobie sprawy, że wszystko, co można zrobić w jQuery, można zrobić w czystym JavaScript. Zaktualizuję odpowiedź ...
www139
2

Próbowałem jeden po drugim i wtedy znalazłem najlepszą odpowiedź:

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

Pomijam stare przeglądarki, więc skróciłem kod do pracy na nowoczesnych przeglądarkach (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>")

Tutaj widzisz obsługę przeglądarki

Pomyślałem, że to było dość krótkie

Ale problem nadal występował, ponieważ "mouseout" uruchamiał się na wszystkich elementach w dokumencie .

Aby temu zapobiec, użyj mouseleave (IE5.5 +). Zobacz dobre wyjaśnienie w linku.

Poniższy kod działa bez wyzwalania elementów wewnątrz elementu, które mają znajdować się wewnątrz lub na zewnątrz. Spróbuj także przeciągnąć i zwolnić poza dokumentem.

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

Możesz ustawić zdarzenie na dowolnym elemencie HTML. Nie document.bodywłączaj jednak zdarzenia, ponieważ pasek przewijania w systemie Windows może zmniejszać zawartość i uruchamiać się, gdy wskaźnik myszy znajduje się nad paskiem przewijania, gdy chcesz przewijać, ale nie chcesz wyzwalać zdarzenia mouseLeave nad nim. documentZamiast tego włącz go , jak w przykładzie.


źródło
1

Może jeśli ciągle słuchasz OnMouseOver w tagu body, wtedy wywołanie zwrotne, gdy zdarzenie nie występuje, ale, jak twierdzi Zack, może to być bardzo brzydkie, ponieważ nie wszystkie przeglądarki obsługują zdarzenia w ten sam sposób, jest nawet kilka możliwość, że stracisz MouseOver, nawet jeśli znajdziesz się nad elementem div na tej samej stronie.

Pablo Albornoz
źródło
To nie jest odpowiedź
1

Może to pomogłoby niektórym z tych, którzy przyjadą tu później. window.onbluridocument.mouseout .

window.onblur jest uruchamiany, gdy:

  • Przełączasz się do innego okna za pomocą Ctrl+TablubCmd+Tab .
  • Skupiasz się (nie tylko najeżdżasz myszą) na inspektorze dokumentów.
  • Zmieniasz komputery.

Zasadniczo za każdym razem, gdy TA karta przeglądarki traci fokus.

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

document.mouseout jest uruchamiany, gdy:

  • Przesuwasz kursor na pasek tytułu.
  • Przełączasz się do innego okna za pomocą Ctrl+TablubCmd+Tab .
  • Po otwarciu przesuń kursor do inspektora dokumentów.

Zasadniczo w każdym przypadku, gdy kursor opuszcza dokument.

document.onmouseleave = function(){
    console.log("Mouse Out!")
}
Jayant Bhawal
źródło
„Zawsze, gdy karta przeglądarki traci fokus”. .. w starszych wersjach IE zdarzenie „blur” jest kompilowane w modelu DOM, gdy / po tym, jak inny element otrzymuje fokus, w przypadku gooChrome jest to sytuacja, w której sam element traci fokus… żeby wspomnieć.
Milche Patern,
Inteligentne użycie window.onblur. +1
Redwolf Programs
1
$(window).mouseleave(function(event) {
  if (event.toElement == null) {
    //Do something
  }
})

To może być trochę hakerskie, ale uruchamia się tylko wtedy, gdy mysz opuści okno. Ciągle łapałem zdarzenia dla dzieci i to rozwiązało problem

Cekaleek
źródło
1
$(window).mouseleave(function() {
 alert('mouse leave');
});
sandeep kumar
źródło
1

To zadziałało dla mnie. Połączenie niektórych odpowiedzi tutaj. I tylko raz zamieściłem kod pokazujący model. Model znika po kliknięciu w innym miejscu.

<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
źródło
W pytaniu nie było żadnego tagu jQuery
mrReiha,
jQuery to dużo kodu w porównaniu z moją odpowiedzią, który działa na nowoczesnych przeglądarkach IE9 + i reszta. Opiera się na tej odpowiedzi, ale jest znacznie krótsza: stackoverflow.com/a/3187524/985399
1

Zobacz mouseoveri 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
źródło
0

Nie testowałem tego, ale moim instynktem byłoby wywołanie funkcji OnMouseOut na tagu body.

Ender
źródło
-2

To zadziała w chrome,

$(document).bind('dragleave', function (e) {
    if (e.originalEvent.clientX == 0){
        alert("left window");
    }
});
anupraj
źródło