Почему я не могу надежно зафиксировать событие мыши? - PullRequest
41 голосов
/ 16 сентября 2011

Мне нужно знать, когда курсор мыши покидает div. Так что я подключаю событие mouseout. Однако, если я очень быстро вывожу мышь из div, событие mouseout не сработает . Правильно: курсор мыши был неподвижно внутри div, теперь он снаружи div, и, тем не менее, обратный вызов mouseout не был вызван. (Работает нормально, если я не так быстро двигаю мышь.)

Кстати, это верно в последней версии Google Chrome , поэтому проблема не только в "старых браузерах".

Обходной путь:

Вопрос об этой проблеме был задан до . По-видимому, это просто факт жизни, и единственный найденный мной обходной путь - это вручную отслеживать mousemove события, каждый раз проверяя координаты курсора x / y и проверяя, попадают ли они в ограничивающую рамку div. Таким образом, у вас больше шансов «заметить», если курсор больше не находится внутри него.

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

На мой вопрос ...

Почему не может браузер не может надежно зафиксировать событие mouseout? Если я могу достоверно определить, когда мышь вышла из div, используя вышеуказанный обходной путь, почему браузер не может это сделать?

Я понимаю (из ответа, приведенного выше), что JavaScript не пытается интерполировать "фреймы". Скажем, если вы поместите обработчик mousemove на document и быстро переместите мышь на 200 пикселей вправо по идеальной горизонтальной линии, вы можете , а не получить 200 mousemove событий. Некоторые будут пропущены. У меня нет проблем с этим.

Но если некоторые движения пикселей пропускаются, когда мышь пересекает границу div, почему из этого следует, что событие mouseout также должно быть пропущено? Когда браузер наконец начинает регистрировать положение мыши снова (после внезапного быстрого движения), даже если мышь теперь находится на расстоянии миль вне коробки, смысл в том, что она раньше находилась в коробке и больше не . Так почему же тогда он не запускает событие mouseout?

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

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

Ответы [ 5 ]

7 голосов
/ 20 сентября 2011

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

Или вы можете перейти к дереву parentNode и остановиться, если найдете свой элемент. Тогда вы знаете, что находитесь внутри элемента и все еще в нем, иначе вы достигнете документа и уйдете.

Некоторые браузеры реализуют события mouseenter / mouseleave, которые, как я заметил, являются более точными, чем mouseout. Prototype и jQuery имеют обходной путь для браузеров, которые не реализуют эти новые события. Mouseleave не срабатывает от дочерних элементов, а mouseout -.

4 голосов
/ 20 сентября 2011

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

Если она вышла наружу, то не обязательно понятно, что должен делать браузер.Событие mouseout должно иметь свойство relatedTarget, которое указывает, во что вошел указатель мыши.Если указатель мыши уже находится за пределами области страницы, не будет связанной цели, на которую можно указать.

Другими словами, когда мышь покидает область страницы, браузер перестает отслеживать ее и сообщает о ее положении.,Если вы перемещаете мышь достаточно быстро, с точки зрения браузера мышь просто исчезла.Только когда вы вернете мышь обратно в ограничивающую рамку видимой страницы, браузер узнает, где она находится, а затем запустит все соответствующие действия, основанные на перемещении (например, перемычка).

1 голос
/ 22 декабря 2016

Я столкнулся с этой проблемой несколько раз, и я пришел к тому, что принял этот факт как факт жизни.Но в зависимости от ваших потребностей, вы можете просто использовать CSS, как я.Например, если я просто хочу показать / скрыть элементную базу на другом элементе, то CSS - это путь.Вот рабочий, надежный пример:

.large {
  width: 175px; height: 175px;
  position: absolute;
  border-radius: 100%;

  /*hide the glass by default*/
  top: -9999px;
  left: -9999px;
  opacity: 0;
  transition: opacity .2s ease-in-out;
  z-index: 100;
  pointer-events: none;
}

.small:hover + .large {
  opacity: 1;
}

http://codepen.io/tanduong/pen/aBMxyd

1 голос
/ 20 сентября 2011
  1. Почему браузер не может надежно зафиксировать событие мыши?Если я могу достоверно определить, когда мышь вышла из div, используя описанный выше обходной путь, почему браузер не может это сделать?

    Я думаю, что вы ответили на это самостоятельно, когда сказали:

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

    Браузер не выполняет интерполяцию между кадрами, поэтомуВы заявили, что это потребует гораздо больше ресурсов и памяти, поэтому, возможно, это и не «исправлено».

  2. Если некоторые движения пикселей пропускаются так же, как мышь пересекаетграница div, почему следует, что событие mouseout также должно быть пропущено?Когда браузер наконец начинает регистрировать положение мыши снова (после внезапного быстрого движения), даже если мышь теперь находится за пределами поля, смысл в том, что она раньше находилась в поле и больше не была.Так почему же тогда он не запускает событие mouseout?

    Не знаю точно, но я не думаю, что это условие «оно было, а теперь нет».Вместо этого, пересекает ли он эту границу (если MouseX - ElemOffsetX= 1).Я согласен, это не имеет особого смысла, но это может быть потому, что если вы установите значение > 1, это вызовет событие несколько раз.В противном случае ему пришлось бы отслеживать события, которые не в JS-природе, а видеть, как он просто добавляет асинхронные события в стек.


Вы можете попробовать использовать Событие jQuery's mouseleave .Это делает две вещи, которые задерживают срабатывание события:

  1. Обходит дерево DOM, чтобы увидеть, действительно ли оно покинуло элемент
  2. Я думаю, что оно реализует вызов тайм-аута, которыйдолжен решить проблему интерполяции, которую вы заметили.
0 голосов
/ 23 июля 2012

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

У меня такая же проблема, когда я использую jquery mouseleave elem.bind ('mouseleave', data, mouseLeavesZone);

Проблема носит неустойчивый характер и может быть связана с занятым процессором на клиенте. Скажем, например, что процессор занят в другом месте, когда ваша мышь выходит из div. Тогда кажется логичным, что это может быть причиной ошибки. Согласен; это должно быть исправлено поставщиками браузеров.

См. http://jsfiddle.net/bgil2012/gWP5x/1/

(Кроме того: мой код JQuery должен использовать более старые методы jQuery, потому что он должен запускаться в Drupal 7, на котором выполняется jQuery 1.4, в настоящее время и без применения будущих исправлений).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...