Pergunta antiga, mas ainda não há uma resposta boa e atualizada com insight imo.
Atualmente, todos os navegadores suportam mouseover/mouseout
e mouseenter/mouseleave
. No entanto, o jQuery não registra seu manipulador mouseenter/mouseleave
, mas silenciosamente os coloca em um invólucro, mouseover/mouseout
como mostra o código a seguir e faz sua própria interpretação ligeiramente diferente mouseenter/mouseleave
.
O comportamento exato dos eventos é especialmente relevante em "delegados manipuladores". Infelizmente, o jQuery também tem sua própria interpretação diferente do que são os manipuladores delegados e o que eles devem receber para eventos. Esse fato é mostrado em outra resposta para o evento de clique mais simples.
Então, como responder adequadamente a uma pergunta sobre o jQuery, que usa o texto Javascript para eventos e manipuladores, mas torna os dois diferentes e nem menciona isso na documentação?
Primeiro as diferenças no Javascript "real":
- ambos
- o mouse pode "pular" de elementos externos / externos para elementos internos / internos quando movido mais rapidamente do que o navegador mostra sua posição
- qualquer
enter/over
um recebe um correspondente leave/out
(possivelmente atrasado / nervoso)
- os eventos vão para o elemento visível abaixo do ponteiro (invisível → não pode ser alvo)
mouseenter/mouseleave
- é entregue ao elemento em que está registrado (destino)
- sempre que o elemento ou qualquer descendente (por exemplo, saltando) for inserido / deixado
- não pode borbulhar, porque conceitualmente os descendentes são considerados parte do elemento em questão, ou seja, não há filhos de onde possa vir outro evento (com o significado de "entrou / saiu" dos pais ?!)
- os filhos também podem ter manipuladores semelhantes registrados, que entram / saem corretamente, mas não relacionados ao ciclo de entrada / saída dos pais
mouseover/mouseout
- o alvo é o elemento real abaixo do ponteiro
- um alvo não pode ser duas coisas: ou seja, pai e filho ao mesmo tempo
- o evento não pode "aninhar"
- antes que uma criança possa ser “exagerada”, os pais precisam sair
- pode borbulhar, porque target / relatedTarget indica onde o evento ocorreu
Após alguns testes, mostra que, desde que você não use o jQuery "delegar manipuladores com registro de seletor", a emulação é desnecessária, mas razoável: filtra os mouseover/mouseout
eventos que mouseenter/mouseleave
não seriam obtidos. O alvo está confuso, no entanto. O real mouseenter/mouseleave
daria o elemento manipulador como alvo, a emulação pode indicar filhos desse elemento, ou seja, o que for mouseover/mouseout
carregado.
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>