Старе запитання, але все ще немає гарної актуальної відповіді з проникливою іммо.
У ці дні всі браузери підтримують mouseover/mouseout
та mouseenter/mouseleave
. Тим не менш, jQuery не реєструє ваш обробник mouseenter/mouseleave
, а мовчки кладе їх на обгортки, mouseover/mouseout
як показано в наступному коді, і робить свою трохи іншу інтерпретацію mouseenter/mouseleave
.
Точна поведінка подій особливо актуальна для "делегованих обробників". На жаль, jQuery також має свою різну інтерпретацію того, що таке обробники делегатов і що вони повинні отримувати для подій. Цей факт показаний в іншій відповіді на простішу подію клацання.
Тож як правильно відповісти на питання про jQuery, який використовує формулювання Javascript для подій та обробників, але робить їх різними і навіть не згадує про це у своїй документації?
По-перше, відмінності у "реальному" Javascript:
- і те й інше
- миша може «перестрибувати» з зовнішніх / зовнішніх елементів до внутрішніх / внутрішніх елементів, коли рухається швидше, ніж браузер відбирає своє положення
- будь-який
enter/over
отримує відповідне leave/out
(можливо, запізнення / стрибки)
- події переходять до видимого елемента під вказівником (невидимий → не може бути націлений)
mouseenter/mouseleave
- доставляється елементу, де зареєстровано (цільовий)
- кожного разу, коли елемент або будь-який нащадок (наприклад, стрибком) вводиться / залишається
- він не може міхур, тому що концептуально нащадків вважають частиною відповідного елемента, тобто немає дітей, з яких могла б відбутися інша подія (зі значенням "введений / залишений" батько ?!)
- діти можуть також зареєструвати подібні обробники, які вводять / залишають правильно, але не мають відношення до батьківського циклу входу / відпустки
mouseover/mouseout
- ціль - фактичний елемент під вказівником
- ціль не може бути двома речами: тобто не батьком і дитиною одночасно
- подія не може «гніздитися»
- перш ніж дитину можна було «пережити», батьку потрібно «вийти»
- може міхур, тому що ціль / relatedTarget вказують, де відбулася подія
Після деякого тестування воно показує, що доки ви не використовуєте jQuery «делегат обробників з реєстрацією селектора», емуляція є непотрібною, але розумною: вона фільтрує mouseover/mouseout
події, до 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>