Vieja pregunta, pero todavía no hay una buena respuesta actualizada con perspicacia de la OMI.
En estos días, todos los navegadores son compatibles mouseover/mouseout
y mouseenter/mouseleave
. Sin embargo, jQuery no registra su manejador mouseenter/mouseleave
, sino que los coloca silenciosamente en envoltorios mouseover/mouseout
como lo muestra el siguiente código y hace su propia interpretación ligeramente diferente demouseenter/mouseleave
.
El comportamiento exacto de los eventos es especialmente relevante en los "controladores de delegados". Desafortunadamente, jQuery también tiene su propia interpretación diferente de qué son los controladores de delegados y qué deben recibir para los eventos. Ese hecho se muestra en otra respuesta para el evento de clic más simple.
Entonces, ¿cómo responder adecuadamente una pregunta sobre jQuery, que utiliza la redacción de Javascript para eventos y controladores, pero hace que ambos sean diferentes y ni siquiera menciona eso en su documentación?
Primero las diferencias en Javascript "real":
- ambos
- el mouse puede "saltar" de elementos externos / externos a elementos internos / internos cuando se mueve más rápido de lo que el navegador muestra su posición
- cualquiera
enter/over
obtiene un correspondiente leave/out
(posiblemente tarde / nervioso)
- los eventos van al elemento visible debajo del puntero (invisible → no puede ser objetivo)
mouseenter/mouseleave
- se entrega al elemento donde está registrado (objetivo)
- siempre que el elemento o cualquier descendiente (por ejemplo, saltando) se ingresa / se deja
- no puede burbujear, porque conceptualmente los descendientes se consideran parte del elemento en cuestión, es decir, no hay niños de donde pueda venir otro evento (¡con el significado de "ingresado / dejado" al padre?)
- los niños también pueden tener controladores similares registrados, que ingresan / salen correctamente, pero no están relacionados con el ciclo de entrada / salida de los padres
mouseover/mouseout
- el objetivo es el elemento real debajo del puntero
- un objetivo no puede ser dos cosas: es decir, no padre e hijo al mismo tiempo
- el evento no puede "anidar"
- antes de que un niño pueda ser "cubierto", el padre necesita "salir"
- puede burbujear, porque target / relatedTarget indica dónde ocurrió el evento
Después de algunas pruebas, muestra que mientras no use jQuery "controladores de delegado con registro de selector", la emulación es innecesaria pero razonable: filtra mouseover/mouseout
eventos que mouseenter/mouseleave
no se obtendrían. Sin embargo, el objetivo está desordenado. Lo real mouseenter/mouseleave
le daría al elemento controlador como objetivo, la emulación podría indicar hijos de ese elemento, es decir, lo que sea que mouseover/mouseout
lleve.
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>