Старый вопрос, но все еще нет хорошего актуального ответа с пониманием IMO.
В наши дни все браузеры поддерживают mouseover/mouseout
и mouseenter/mouseleave
. Тем не менее, jQuery не регистрирует ваш обработчик mouseenter/mouseleave
, но молча помещает их в обертки, mouseover/mouseout
как показано в следующем коде, и дает свою немного отличную интерпретацию mouseenter/mouseleave
.
Точное поведение событий особенно важно для «обработчиков делегатов». К сожалению, jQuery также имеет свою собственную интерпретацию того, что представляют собой обработчики делегатов и что они должны получать для событий. Этот факт показан в другом ответе для более простого события щелчка.
Итак, как правильно ответить на вопрос о jQuery, который использует формулировку Javascript для событий и обработчиков, но делает оба отличия и даже не упоминает об этом в своей документации?
Сначала различия в «реальном» Javascript:
- обе
- мышь может «перепрыгивать» из внешних / внешних элементов во внутренние / самые внутренние элементы, когда она перемещается быстрее, чем браузер определяет ее положение
- любой
enter/over
получает соответствующий leave/out
(возможно поздно / нервный)
- события идут к видимому элементу под указателем (невидимый → не может быть целью)
mouseenter/mouseleave
- доставляется до элемента, где зарегистрирован (цель)
- всякий раз, когда элемент или любой потомок (например, путем прыжка) вводится / оставляется
- он не может пузыриться, потому что концептуально потомки считаются частью рассматриваемого элемента, то есть нет дочерних элементов, из которых могло бы произойти другое событие (со значением «ввели / оставили» родительский элемент ?!)
- у детей также могут быть зарегистрированы похожие обработчики, которые вводятся / уходят правильно, но не связаны с родительским циклом ввода / вывода
mouseover/mouseout
- цель - фактический элемент под указателем
- целью не может быть две вещи: т.е. не родитель и ребенок одновременно
- событие не может «гнездиться»
- прежде чем ребенок может быть «переедан», родитель должен «выйти»
- может всплыть, потому что target / relatedTarget указывает, где произошло событие
После некоторого тестирования это показывает, что пока вы не используете jQuery «делегировать обработчики с регистрацией селектора», эмуляция не нужна, но разумна: она отфильтровывает mouseover/mouseout
события, которые a mouseenter/mouseleave
не получит. Цель перепутана, хотя. Реальный mouseenter/mouseleave
даст элемент обработчика в качестве цели, эмуляция может указывать на потомок этого элемента, то есть независимо от mouseover/mouseout
проводимого.
const list = document.getElementById('log');
const outer = document.getElementById('outer');
const $outer = $(outer);
function log(tag, event) {
const li = list.insertBefore(document.createElement('li'), list.firstChild);
// only jQuery handlers have originalEvent
const e = event.originalEvent || event;
li.append(`${tag} got ${e.type} on ${e.target.id}`);
}
outer.addEventListener('mouseenter', log.bind(null, 'JSmouseenter'));
$outer.on('mouseenter', log.bind(null, '$mouseenter'));
div {
margin: 20px;
border: solid black 2px;
}
#inner {
min-height: 80px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<div id=outer>
<ul id=log>
</ul>
</div>
</body>