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/mouseouty mouseenter/mouseleave. Sin embargo, jQuery no registra su manejador mouseenter/mouseleave, sino que los coloca silenciosamente en envoltorios mouseover/mouseoutcomo 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/overobtiene 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/mouseouteventos que mouseenter/mouseleaveno se obtendrían. Sin embargo, el objetivo está desordenado. Lo real mouseenter/mouseleavele daría al elemento controlador como objetivo, la emulación podría indicar hijos de ese elemento, es decir, lo que sea que mouseover/mouseoutlleve.
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>