jQuery / Método / .hover() - Entrada, saída e alternativas com on
No jQuery, .hover() é um atalho para registrar funções quando o ponteiro entra e sai de um elemento. Está obsoleto desde o jQuery 3.3; em código novo use .on("mouseenter", ...) e .on("mouseleave", ...). Obsoleto não significa removido: as duas abordagens abaixo foram executadas com 3.7.1 e 4.0.0.
Duas funções ou uma função compartilhada
A forma de duas funções de .hover() chama a primeira na entrada e a segunda na saída. Registra mouseenter e mouseleave, não um evento chamado hover.
| Forma anterior | Substituição | Significado |
|---|---|---|
| .hover(enter, leave) | .on("mouseenter", enter).on("mouseleave", leave) | Funções separadas para entrada e saída |
| .hover(handler) | .on("mouseenter mouseleave", handler) | Uma função para os dois eventos |
mouseenter considera o limite do elemento. Se o ponteiro já está dentro do pai e vai ao span filho, não entra novamente no pai. Isso difere do mouseover propagado por transições dos filhos e evita essas repetições indesejadas.
Exemplo completo de hover e on
Salve todo o código em UTF-8 como hover-demo.html e abra no navegador. É preciso internet para carregar o arquivo oficial do jQuery 4.0.0 pela rede de distribuição de conteúdo, CDN, sem instalar pacotes. Os dois exemplos, transições dos filhos, elementos dinâmicos, teclado e remoção foram executados com 3.7.1 e 4.0.0.
Alpha usa .hover() e Beta usa .on() delegado por #cards. O conteúdo fica sempre visível; só muda o destaque. Beta também trata focusin/focusout para o foco de teclado.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Hover events and keyboard focus</title>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<style>
body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 24px auto; padding: 16px; }
button { font: inherit; margin: 6px; }
.card { display: block; padding: 20px; border: 2px solid teal; background: white; }
.active { background: #d9f4ef; }
.card:focus-visible { outline: 3px solid #af5f00; outline-offset: 3px; }
</style>
</head>
<body>
<h1>Compare legacy hover and on</h1>
<button type="button" id="add">Add modern card</button>
<button type="button" id="bind">Bind modern</button>
<button type="button" id="unbind">Unbind modern</button>
<button type="button" id="reset">Reset</button>
<div id="cards">
<button type="button" class="card legacy">Legacy <span>Alpha</span></button>
<button type="button" class="card modern">Modern <span>Beta</span></button>
</div>
<p id="result" aria-live="polite"></p>
<script>
$(function () {
const $cards = $("#cards");
let legacyEntries = 0;
let modernEntries = 0;
function report() {
$("#result").text(`legacy enters=${legacyEntries} | modern enters=${modernEntries}`);
}
$(".legacy").hover(function () {
legacyEntries++;
$(this).addClass("active");
report();
}, function () { $(this).removeClass("active"); });
function bindModern() {
$cards.off(".hoverLesson").on(
"mouseenter.hoverLesson mouseleave.hoverLesson focusin.hoverLesson focusout.hoverLesson",
".modern", function (event) {
const $card = $(this);
if (event.type === "mouseenter") { $card.data("inside", true); modernEntries++; }
if (event.type === "mouseleave") $card.data("inside", false);
if (event.type === "focusin") $card.data("focused", true);
if (event.type === "focusout") $card.data("focused", false);
$card.toggleClass("active", Boolean($card.data("inside") || $card.data("focused")));
report();
}
);
}
$("#bind").on("click", bindModern);
$("#unbind").on("click", function () {
$cards.off(".hoverLesson");
$(".modern").removeClass("active").removeData("inside focused");
});
$("#add").on("click", function () {
if (!$("#gamma").length) $('<button type="button" id="gamma" class="card modern">Modern <span>Gamma</span></button>').appendTo($cards);
});
$("#reset").on("click", function () {
$("#gamma").remove();
$(".card").removeClass("active").removeData("inside focused");
legacyEntries = 0;
modernEntries = 0;
bindModern();
report();
});
bindModern();
report();
});
</script>
</body>
</html>
Os dois contadores de entrada começam em zero:
legacy enters=0 | modern enters=0
- Entre em Legacy Alpha. O fundo muda e legacy enters aumenta uma vez. Ir ao span Alpha interno não aumenta novamente.
- Saia para remover o destaque. Modern Beta aumenta modern enters a cada entrada.
- Add modern card cria Gamma. O manipulador delegado do pai trata o novo cartão sem registro individual.
- Use Tab para focar Beta. Fundo e contorno aparecem. Se apenas o ponteiro sair, o fundo permanece enquanto houver foco; ambos precisam sair para remover o destaque.
- Unbind modern desativa apenas Modern. O hover de Alpha continua funcionando.
- Repetir Bind modern não duplica chamadas. Reset remove Gamma e destaques, zera contadores e reconecta Modern.
inside e focused controlam ponteiro e foco separadamente. Um deles basta para manter o destaque. Remover a classe sempre em mouseleave apagaria a indicação mesmo com foco de teclado restante.
Elementos dinâmicos e alcance da remoção
A forma delegada de .on() se conecta a um pai estável com seletor de descendentes. Aqui #cards permanece e trata apenas botões .modern. .hover() conecta diretamente a seleção existente no registro; elementos futuros não herdam automaticamente o manipulador.
hoverLesson é um namespace de eventos. bindModern() chama primeiro .off(".hoverLesson") para remover somente os próprios manipuladores e depois registrar novamente. .off() sem argumento ou um .off("mouseenter mouseleave") amplo pode remover os de outros componentes.
Em uma function comum, this é o cartão Modern tratado. Difere de event.target, que pode ser o span interno onde o evento surgiu. Não troque indiscriminadamente por função de seta se precisar desse this.
Função única e formas de entrada
Execute este trecho completo no Console das ferramentas de desenvolvimento para observar os dois tipos na mesma função. Ele dispara eventos em um botão temporário não inserido e o limpa depois. O movimento real do ponteiro é observado no exemplo completo.
const events = [];
const $button = $("<button>Temporary</button>");
$button.hover(function (event) { events.push(event.type); });
$button.trigger("mouseenter").trigger("mouseleave");
console.log(events.join(", "));
$button.remove();
mouseenter, mouseleave
São entrada e saída, não captura contínua de cada movimento. Verificar event.type e definir o estado explicitamente evita que um toggle simples fique invertido depois de outras mudanças.
Não dependa apenas de hover do mouse para revelar conteúdo essencial em telas sensíveis ao toque. Ofereça clique/toque e teclado nas funções importantes. Para decoração, CSS :hover e :focus-visible podem bastar. O exemplo sempre mostra o conteúdo e altera apenas o destaque.




