jQuery / Methode / .hover() - Eintritt und Austritt mit on ersetzen

jQuerys .hover() registriert verkürzt Funktionen für das Betreten und Verlassen eines Elements durch den Mauszeiger. Seit jQuery 3.3 ist es veraltet; neuer Code sollte .on("mouseenter", ...) und .on("mouseleave", ...) verwenden. Veraltet bedeutet nicht entfernt: Beide Ansätze unten wurden mit 3.7.1 und 4.0.0 ausgeführt.

Zwei Funktionen oder eine gemeinsame Funktion

Die Zwei-Funktionen-Form von .hover() ruft die erste beim Eintritt, die zweite beim Austritt auf. Es wird kein Ereignis namens hover registriert, sondern mouseenter und mouseleave.

Alte Form Ersatz Bedeutung
.hover(enter, leave) .on("mouseenter", enter).on("mouseleave", leave) Getrennte Funktionen für Eintritt und Austritt
.hover(handler) .on("mouseenter mouseleave", handler) Eine Funktion für beide Ereignisse

mouseenter betrifft die Elementgrenze. Ein Zeiger, der sich bereits im Elternteil befindet und zum inneren span bewegt, betritt den Elternteil nicht erneut. Anders als mouseover mit Weitergabe aus Kindübergängen vermeidet das unnötige wiederholte Aufrufe.

Vollständiger Vergleich von hover und on

Speichern Sie alles in UTF-8 als hover-demo.html und öffnen Sie es im Browser. Zum Laden der offiziellen jQuery-Datei 4.0.0 vom Content Delivery Network (CDN) brauchen Sie Internet, aber keine Paketinstallation. Beide Beispiele, Kindübergänge, dynamische Elemente, Tastatur und Entfernen wurden mit 3.7.1 und 4.0.0 ausgeführt.

Alpha verwendet .hover(), Beta ein von #cards delegiertes .on(). Karteninhalte bleiben sichtbar, nur die Hervorhebung ändert sich. Beta erhält zusätzlich focusin/focusout für Tastaturfokus.

<!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>

Anfangs stehen beide Eintrittszähler auf null:

legacy enters=0 | modern enters=0
  1. Bewegen Sie den Zeiger in Legacy Alpha. Hintergrund und legacy enters ändern sich einmal. Bewegung auf den inneren Alpha-span erhöht nicht erneut.
  2. Beim Verlassen verschwindet die Hervorhebung. Modern Beta erhöht entsprechend modern enters bei jedem Eintritt.
  3. Add modern card erzeugt Gamma. Der delegierte Elternhandler behandelt die neue Karte ohne gesonderte Registrierung.
  4. Fokussieren Sie Beta mit Tab. Hintergrund und Fokusrahmen erscheinen. Verlässt nur der Zeiger die Karte, bleibt der Hintergrund mit dem Fokus bestehen. Erst wenn beide weg sind, endet die Hervorhebung.
  5. Unbind modern deaktiviert nur Modern. Alphas alter hover bleibt aktiv.
  6. Wiederholtes Bind modern dupliziert keine Aufrufe. Reset entfernt Gamma und Hervorhebungen, setzt Zähler auf null und verbindet Modern erneut.

inside und focused verwalten Zeiger und Fokus getrennt; einer genügt für die Hervorhebung. Würde mouseleave immer die Klasse löschen, ginge die visuelle Anzeige trotz verbleibendem Tastaturfokus verloren.

Dynamische Elemente und Entfernungsbereich

Die delegierte .on()-Form bindet an einen beständigen Elternteil mit Nachfahrenselektor. Hier bleibt #cards erhalten und behandelt nur .modern-Buttons. .hover() bindet direkt an die bei Registrierung gewählten Elemente; spätere Elemente übernehmen den Handler nicht automatisch.

hoverLesson ist ein Ereignisnamensraum. bindModern() entfernt mit .off(".hoverLesson") zunächst nur die eigenen Handler und bindet danach neu. .off() ohne Argument oder breites .off("mouseenter mouseleave") könnte fremde Handler entfernen; grenzen Sie den Bereich ein.

In der normalen function ist this die behandelte Modern-Karte. event.target kann dagegen der innere span sein, an dem das Ereignis entstand. Ersetzen Sie die Funktion nicht unbedacht durch eine Pfeilfunktion, wenn Sie diese this-Bindung benötigen.

Gemeinsamen Handler und Eingabemöglichkeiten prüfen

Führen Sie diesen vollständigen Teilcode in der Entwicklerkonsole aus, um beide Ereignistypen an einer Funktion zu beobachten. Er löst Ereignisse an einem nicht eingefügten temporären Button aus und bereinigt ihn anschließend. Echte Zeigerbewegungen zeigt das vollständige Beispiel.

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

Die Ausgabe bedeutet Eintritt und Austritt, nicht fortlaufende Erfassung jeder Mausbewegung. Mit event.type und ausdrücklichen Zuständen lässt sich vermeiden, dass ein einfaches toggle nach anderen Änderungen verkehrt steht.

Wichtige Inhalte auf Touchscreens sollten nicht allein über Maus-hover erreichbar sein. Bieten Sie Klick/Tippen und Tastaturzugang an. Für reine Dekoration können CSS :hover und :focus-visible genügen. Das Beispiel zeigt den Karteninhalt immer und verändert nur die Hervorhebung.