Как я могу определить, когда мышь покидает окно?

102

Я хочу иметь возможность определять, когда мышь покидает окно, чтобы я мог остановить запуск событий, пока мышь пользователя находится в другом месте.

Есть идеи, как это сделать?


источник
1
Ознакомьтесь с этой библиотекой github для выхода beeker. Здорово. github.com/beeker1121/exit-intent-popup
raksheetbhat
Используйте mouseleave, чтобы предотвратить запуск всех элементов, как это делает mouseout : очень хорошее объяснение и поддержка: developer.mozilla.org/en-US/docs/Web/API/Element/…
Установите событие в документе, а не в document.body, чтобы предотвратить срабатывание полосы прокрутки. Полоса прокрутки Windows, кажется, сжимает тело.

Ответы:

100

Имейте в виду, что мой ответ сильно устарел.

Этот тип поведения обычно желателен при реализации поведения перетаскивания на html-странице. Приведенное ниже решение было протестировано в IE 8.0.6, FireFox 3.6.6, Opera 10.53 и Safari 4 на компьютере с MS Windows XP.
Сначала небольшая функция от Peter-Paul Koch; кроссбраузерный обработчик событий:

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

А затем используйте этот метод для присоединения обработчика событий к событию mouseout объектов документа:

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

Наконец, вот html-страница со встроенным скриптом для отладки:

<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>
Дж. Миллс
источник
Использование window.event устранило мою проблему с получением этого события. Спасибо!
Джей
похоже, что это не срабатывает, когда мышь не нажата в хроме. он срабатывает при нажатии мыши в хроме. кажется непоследовательным поведением.
antony.trupe
5
Это не работает, если окно заполняют другие элементы HTML.
Эммануэль
Проблема с этим решением заключается в том, что оно предупреждает левое окно, даже если пользователь просто пытается использовать скроллер. Я опубликовал решение этой проблемы здесь , но есть еще одна проблема, которую нужно решить (см. Ссылку).
JohnyFree
1
Используйте mouseleave вместо mouseout, чтобы предотвратить возгорание элементов в документе. Очень хорошее объяснение, и оно работает в IE5.5 ... developer.mozilla.org/en-US/docs/Web/API/Element/…
43

Если вы используете jQuery, то как насчет этого короткого и приятного кода -

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

Это событие будет срабатывать всякий раз, когда указатель мыши не находится на вашей странице, как вы хотите. Просто измените функцию на то, что хотите.

И вы также можете использовать:

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

Срабатывать, когда мышь снова возвращается на страницу.

Источник: https://stackoverflow.com/a/16029966/895724

Мандип Джанджуа
источник
mouseleave работает, но также срабатывает, если открыт элемент проверки, как предотвратить? Идея?
Панкай Верма
Этот метод нестабилен в Chrome с 15 по 56 (моя текущая версия). Но в Firefox это работает очень будет. См .: stackoverflow.com/questions/7448468/…
Tremours
mouseleave, кажется, срабатывает намного больше, чем следует.
Александр
Он также срабатывает, если окно находится в фоновом режиме (браузер не сфокусирован) и мышь входит в окно (Chrome 61 / macOS10.11)
CodeBrauer 03
1
@Skeets (и будущие читатели) Эта проблема была отмечена как исправленная с 14 февраля 2019 г.
Xandor
27

Это работает для меня:

addEvent(document, 'mouseout', function(evt) {
  if (evt.toElement == null && evt.relatedTarget == null) {
    alert("left window");
  }
});
user1084282
источник
9
Что есть addEvent?
Yi Jiang
5
это функция, определенная в ответе Джошуа Миллса
superjos
4
в ie8 relatedTarget не определен, в ie9 + и firefox toElement не определен. Потому что это правильная оценка: if ((evt.relatedTarget === null) || (evt.toElement === null)) {
carlos
1
Предикат мог быть более кратким, напримерif (!evt.toElement && !evt.relatedTarget)
Павел Е
20

Чтобы обнаружить оставление мыши без учета полосы прокрутки и поля автозаполнения или проверьте:

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

  }
});

Пояснения к условиям:

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

======================== РЕДАКТИРОВАТЬ ========================= ======

document.addEventListener ("mouseleave"), похоже, не запускается в новой версии Firefox, mouseleave необходимо прикрепить к такому элементу, как body, или дочернему элементу.

Я предлагаю вместо этого использовать

document.body.addEventListener("mouseleave")

Или

window.addEventListener("mouseout")
Дафок
источник
время от времени не стреляли. Кажется, что это не работает, когда одна точка потока точек, вызванная перемещением курсора, нацеливается на границу, а размер курсора изменяется.
Иван Борщов
@ user3479125, не могли бы вы также попробовать это в моем фрагменте и посмотреть, останется ли проблема, когда оператор if не добавлен? Он принимает во внимание полосу прокрутки, но я не тестировал с автозаполнением или проверкой. stackoverflow.com/a/56678357/985399
7

Использование события onMouseLeave предотвращает всплытие и позволяет легко определять, когда мышь покидает окно браузера.

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

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

Сами Бенчериф
источник
Фантастика! Поддержка IE5.5 + ... Также работает: document.onmouseleave = function() { alert('You left!') };используйте не document.body, которое запускает полосы прокрутки, которые сжимают тело! Код для предотвращения возгорания элементов не требуется. Хорошее объяснение: developer.mozilla.org/en-US/docs/Web/API/Element/…
6

Ни один из этих ответов не помог мне. Сейчас я использую:

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

});

Я использую это для виджета загрузки файлов методом перетаскивания. Это не совсем точно, срабатывает, когда мышь приближается к определенному расстоянию от края окна.

Эммануэль
источник
Я считаю, что это иногда не срабатывает, если движение мыши «достаточно быстрое».
Джон Вайс
@JohnWeisz Да, я думаю, ты прав. Я уже некоторое время использую этот скрипт, но он работает хорошо.
Эммануэль
6

Я пробовал все вышеперечисленное, но ничего не работает, как ожидалось. После небольшого исследования я обнаружил, что e.relatedTarget - это html непосредственно перед тем, как мышь покинет окно .

Итак ... В итоге я получил следующее:


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

Пожалуйста, дайте мне знать, если вы обнаружите какие-либо проблемы или улучшения!

Обновление 2019

(как выяснил user1084282)

document.body.addEventListener('mouseout', function(e) {
    if (!e.relatedTarget && !e.toElement) {
        console.log('We\'re OUT !');
    }
});
Клаудиу
источник
2
У меня не работает хром. relatedTargetимеет значение null, когда мышь покидает окно. Вдохновленный ответом @ user1084282, измените его на это: if(!e.relatedTarget && !e.toElement) { ... }и он работает
Я подтверждаю, что это нормально работает в Chrome, Firefox и IE Edge, если вы используете if(!e.relatedTarget && !e.toElement)вместо условия в фактическом ответе. Он обнаруживает, что мышь покидает тело документа.
Haijerome
Нет события в document.body, потому что полоса прокрутки Windows может сузить его и сработать при прокрутке. И почему у вас есть «mouseout», который срабатывает для всех всплывающих элементов, когда можно «mouseleave»? developer.mozilla.org/en-US/docs/Web/API/Element/…
2

Я беру то, что сказал. Это возможно. Я написал этот код, работает отлично.

window.onload = function() {

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

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

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

}

работает в chrome, firefox, opera. Не тестировался в IE, но предполагаю, что он работает.

редактировать. IE как всегда доставляет неприятности. Чтобы он работал в IE, замените события из окна на документ:

window.onload = function() {

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

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

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

}

объедините их для обнаружения курсора в кроссбраузере o0: P

Оззи
источник
Вы проверяли, насколько хорошо это работает с элементами на странице? Я бы подумал, что элементы, у которых есть свои собственные события onmouseover / out, потенциально могут отменить всплытие и нарушить эту функциональность.
Дэн Герберт
1
Оззи, Дэн пытается объяснить, что элемент, который останавливает распространение события, не позволит событию достичь документа / окна, что сделает ваше решение неэффективным.
Джеймс
Я только что протестировал его с другими элементами с их собственными событиями onmousemove и onmouseout, и он по-прежнему работает нормально.
Оззи
2
Да ладно, но мы снова говорим о распространении событий. Если вы намеренно остановите распространение события с помощью EVENT.stopPropagation () (для IE, EVENT.cancelBubble = true), тогда он не будет пузыриться до документа / окна ... Чтобы противодействовать этому, вы можете использовать захват событий в браузерах, которые его поддерживают .
Джеймс
Помните, что в JS для объявления переменной вы должны использовать var. Теперь переменная $ span является неявной глобальной, что, вероятно, не то, что вам нужно. Также, если это не намеренно, вам не нужен $ в именах переменных.
Jani Hartikainen
2

примените этот css:

html
{
height:100%;
}

Это гарантирует, что элемент html займет всю высоту окна.

примените этот jquery:

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

Проблема с наведением указателя мыши и наведением указателя мыши заключается в том, что если вы наведете указатель мыши на дочерний элемент или выйдете из него, это вызовет событие. Функция, которую я дал , не активируется при наведении указателя мыши на дочерний элемент. Он срабатывает только при выходе / вхождении курсора мыши в окно

просто чтобы вы знали, что вы можете это сделать, когда пользователь наводит курсор мыши в окне:

$("html").mouseenter(function(){
  alert('mouse enter');
});
www139
источник
2
Говоря «Я не верю, что у javascript есть эквивалентная функция», вы имеете в виду, что вы не знаете, что jQuery ЯВЛЯЕТСЯ библиотекой функций javascript и что jQuery написан с использованием javascript и ДЛЯ него?
Milche Patern 09
2
@MilchePatern Я написал этот ответ почти два года назад. Тогда я был более невежественным и не осознавал того факта, что все, что делается в jQuery, можно делать на чистом JavaScript. Я
обновлю
2

Я пробовал один за другим и нашел лучший ответ на тот момент:

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

Я не использую старые браузеры, поэтому сделал код короче для работы в современных браузерах (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>")

Здесь вы видите поддержку браузера

Это было довольно коротко, я думал

Но проблема все еще оставалась, потому что «mouseout» срабатывает для всех элементов в документе .

Чтобы этого не произошло, используйте mouseleave (IE5.5 +). См. Хорошее объяснение по ссылке.

Следующий код работает без срабатывания по элементам внутри элемента, которые должны быть внутри или снаружи. Попробуйте также перетащить за пределы документа.

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

Вы можете установить событие для любого HTML-элемента. Однако не document.bodyвключайте событие , потому что полоса прокрутки Windows может сжимать тело и срабатывать, когда указатель мыши находится над полосой прокрутки, когда вы хотите прокручивать, но не хотите запускать событие mouseLeave над ней. documentВместо этого установите его , как в примере.


источник
1

Может быть, если вы постоянно слушаете OnMouseOver в теге body, а затем обратный вызов, когда событие не происходит, но, как утверждает Зак, это может быть очень уродливым, потому что не все браузеры обрабатывают события одинаково, есть даже некоторые возможность того, что вы потеряете MouseOver, даже если окажетесь над div на той же странице.

Пабло Альборнос
источник
Это не ответ
1

Может быть, это поможет некоторым из тех, кто придет сюда позже. window.onblurи document.mouseout.

window.onblur срабатывает, когда:

  • Вы переключаетесь в другое окно с помощью Ctrl+Tabили Cmd+Tab.
  • Вы фокусируетесь (а не только при наведении указателя мыши) на инспектор документов.
  • Вы переключаете рабочие столы.

Практически всегда, когда ТАКАЯ вкладка браузера теряет фокус.

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

document.mouseout срабатывает, когда:

  • Вы перемещаете курсор на строку заголовка.
  • Вы переключаетесь в другое окно с помощью Ctrl+Tabили Cmd+Tab.
  • Вы открываете, перемещаете курсор на инспектор документов.

Практически в любом случае, когда ваш курсор покидает документ.

document.onmouseleave = function(){
    console.log("Mouse Out!")
}
Джаянт Бхавал
источник
"как правило, в любое время, когда ТАКАЯ вкладка браузера теряет фокус". ... в более старых версиях IE событие 'blur' скомпилировано в DOM, когда / после того, как другой элемент получает фокус, для gooChrome это происходит, когда сам элемент теряет фокус ... просто чтобы упомянуть.
Milche Patern 09
Умное использование window.onblurтоже. +1
Redwolf Programme
1
$(window).mouseleave(function(event) {
  if (event.toElement == null) {
    //Do something
  }
})

Это может быть немного взломано, но срабатывает только тогда, когда мышь покидает окно. Я продолжал ловить дочерние события, и это решило проблему.

Cekaleek
источник
1
$(window).mouseleave(function() {
 alert('mouse leave');
});
Сандип Кумар
источник
1

Это сработало для меня. Комбинация некоторых ответов здесь. И я включил код, показывающий модель, только один раз. И модель уходит, если щелкнуть где-нибудь еще.

<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>
Морган Хейс
источник
В вопросе не было тега jQuery
mrReiha
jQuery - это много кода по сравнению с моим ответом, который работает в современных браузерах IE9 + и остальных. Он
1

Смотрите mouseoverи 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
источник
0

Я не тестировал это, но моим инстинктом было бы выполнить вызов функции OnMouseOut для тега body.

Эндер
источник
-2

Это будет работать в хроме,

$(document).bind('dragleave', function (e) {
    if (e.originalEvent.clientX == 0){
        alert("left window");
    }
});
анупрадж
источник