Stare pytanie, ale nadal nie ma dobrej, aktualnej odpowiedzi z wglądem imo.
Obecnie wszystkie przeglądarki obsługują mouseover/mouseout
i mouseenter/mouseleave
. Niemniej jednak jQuery nie rejestruje programu obsługi mouseenter/mouseleave
, ale po cichu umieszcza je w opakowaniach, mouseover/mouseout
jak pokazuje poniższy kod, i tworzy własną, nieco inną interpretację mouseenter/mouseleave
.
Dokładne zachowanie zdarzeń jest szczególnie istotne w przypadku „obsługi delegatów”. Niestety, jQuery ma również inną interpretację tego, czym są programy obsługi delegatów i co powinny otrzymywać dla zdarzeń. Fakt ten pokazuje inna odpowiedź dotycząca prostszego zdarzenia kliknięcia.
Jak więc właściwie odpowiedzieć na pytanie o jQuery, które używa sformułowań Javascript dla zdarzeń i handlerów, ale różni je i nawet nie wspomina o tym w swojej dokumentacji?
Najpierw różnice w „prawdziwym” JavaScript:
- obie
- mysz może „przeskakiwać” z elementów zewnętrznych / zewnętrznych do elementów wewnętrznych / najbardziej wewnętrznych, gdy jest poruszana szybciej niż przeglądarka sprawdza jej położenie
- każdy
enter/over
dostaje odpowiedni leave/out
(prawdopodobnie późny / niespokojny)
- zdarzenia przechodzą do widocznego elementu poniżej wskaźnika (niewidoczne → nie mogą być celem)
mouseenter/mouseleave
- jest dostarczany do elementu, w którym został zarejestrowany (docelowy)
- ilekroć element lub dowolny element podrzędny (np. przeskakując) jest wprowadzany / opuszczany
- nie może bąbelkować, ponieważ koncepcyjnie potomkowie są uważani za część rozpatrywanego elementu, tj. nie ma dzieci, z których mogłoby pochodzić inne zdarzenie (w znaczeniu „wszedł / opuścił” rodzica ?!)
- dzieci mogą również mieć zarejestrowanych podobnych opiekunów, którzy wchodzą / wychodzą poprawnie, ale nie są związani z cyklem wejścia / wyjścia rodziców
mouseover/mouseout
- celem jest rzeczywisty element poniżej wskaźnika
- celem nie mogą być dwie rzeczy: tj. nie rodzic i dziecko w tym samym czasie
- wydarzenie nie może „zagnieździć”
- zanim dziecko będzie mogło się „ogarnąć”, rodzic musi „wyjść”
- can bubble, ponieważ target / relatedTarget wskazują, gdzie wystąpiło zdarzenie
Po kilku testach okazuje się, że dopóki nie używasz „obsługi delegatów z rejestracją selektora” jQuery, emulacja jest niepotrzebna, ale rozsądna: odfiltrowuje mouseover/mouseout
zdarzenia, mouseenter/mouseleave
których nie uzyska. Jednak cel jest pomieszany. Rzeczywiste mouseenter/mouseleave
wskazywałyby element obsługujący jako cel, emulacja mogłaby wskazywać dzieci tego elementu, tj. Cokolwiek jest mouseover/mouseout
przenoszone.
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>