W3docs

JavaScript Mausbewegungen: mouseover/out, mouseenter/leave

Unterschiede zwischen mouseover/mouseout und mouseenter/mouseleave in JavaScript: Bubbling, relatedTarget, das Kind-Element-Problem und ausführbare Beispiele.

Mausbewegungsereignisse in JavaScript verstehen: Mouseover, Mouseout, Mouseenter und Mouseleave

Mausbewegungsereignisse (events) in JavaScript ermöglichen Entwicklern, auf die Bewegung des Cursors über Elemente einer Webseite zu reagieren. Diese Ereignisse sind entscheidend für die Erstellung interaktiver und reaktionsfähiger Oberflächen, die auf Benutzeraktionen reagieren. Dieser Leitfaden erläutert die Unterschiede zwischen den Ereignissen mouseover, mouseout, mouseenter und mouseleave und bietet praktische Beispiele zur Veranschaulichung ihrer Verwendung.

Die zwei Ereignispaare im Überblick

JavaScript bietet zwei Ereignispaare für dieselbe physische Aktion — der Zeiger bewegt sich auf ein Element zu oder von ihm weg. Sie wirken austauschbar, verhalten sich jedoch bei Kind-Elementen sehr unterschiedlich, und die Wahl des falschen Paares ist einer der häufigsten UI-Fehler.

EreignisWird ausgelöst, wenn der Zeiger…Bubbling?Erneut bei Kind-Elementen?
mouseoverdas Element oder einen Nachfahren betrittJaJa
mouseoutdas Element oder einen Nachfahren verlässtJaJa
mouseenterdie eigene Grenze des Elements betrittNeinNein
mouseleavedie eigene Grenze des Elements verlässtNeinNein

Mouseover und Mouseout

  • mouseover: Wird ausgelöst, wenn die Maus das Element oder eines seiner Kind-Elemente betritt. Da es bubbles (nach oben weitergegeben wird), ist es die richtige Wahl für Event-Delegation — ein einzelner Listener auf einem Container kann das Hovern über viele Kind-Elemente verwalten.
  • mouseout: Das Gegenstück zu mouseover — wird ausgelöst, wenn die Maus das Element oder eines seiner Kind-Elemente verlässt.

Der Haken dabei ist, dass das Bewegen des Zeigers von einem Elternelement auf ein Kind-Element mouseout auf dem Elternelement auslöst (der Zeiger hat den Textbereich des Elternelements „verlassen"), unmittelbar gefolgt von mouseover (er hat das Kind betreten, das noch zum Elternelement zählt). Ein einzelner visueller Hover kann also einen unruhigen Ereignisstrom auf einem Elternelement mit Kind-Elementen erzeugen.

Mouseenter und Mouseleave

  • mouseenter: Ähnlich wie mouseover, aber es bubbles nicht und wird nicht erneut ausgelöst, wenn der Zeiger ein Kind-Element betritt. Es wird genau einmal ausgelöst, wenn der Zeiger erstmals die Grenze des Elements überschreitet — ideal für das Verhalten „diese Karte beim Hovern hervorheben".
  • mouseleave: Wird einmal ausgelöst, wenn der Zeiger die äußere Grenze des Elements verlässt, ohne Bewegungen zwischen Nachfahren zu berücksichtigen.

Faustregel: Verwenden Sie mouseenter/mouseleave, wenn Sie eine klare „Befindet sich der Zeiger über diesem Element?"-Logik benötigen, und mouseover/mouseout nur dann, wenn Sie Bubbling für die Delegation benötigen.

Die relatedTarget-Eigenschaft

Beide Ereignisse stellen event.relatedTarget bereit, das Ihnen das andere Element angibt, das am Übergang beteiligt ist:

  • Bei mouseover/mouseenter ist relatedTarget das Element, von dem der Zeiger kam.
  • Bei mouseout/mouseleave ist relatedTarget das Element, zu dem der Zeiger sich bewegt.

So können Sie das Verhalten von mouseenter nachbilden, während Sie weiterhin die bubbelnden Ereignisse mouseover/mouseout verwenden: Prüfen Sie, ob relatedTarget sich innerhalb des aktuellen Elements befindet, und ignorieren Sie das Ereignis, wenn dies der Fall ist.

element.addEventListener('mouseout', function (event) {
  // Ignore transitions to a descendant — only react to truly leaving.
  if (this.contains(event.relatedTarget)) return;
  console.log('Pointer really left the element');
});

Beachten Sie, dass relatedTarget null sein kann — zum Beispiel wenn der Zeiger von außerhalb des Browserfensters kommt — daher sollten Sie es absichern, bevor Sie contains() aufrufen.

Ein häufiger Fallstrick: die „schnelle Mausbewegung"

mouseover/mouseout werden nicht garantiert für jedes Element ausgelöst, über das der Zeiger fährt. Wenn der Benutzer die Maus sehr schnell bewegt, können zwischenliegende Elemente vollständig übersprungen werden, und Sie können ein mouseout für ein Element erhalten, ohne ein passendes mouseover für das nächste. Code, der diese beiden Ereignisse kombiniert, muss fehlende Gegenstücke tolerieren. mouseenter/mouseleave sind für das betreffende Element immer ausgewogen, was ein weiterer Grund ist, sie für das Zustandstracking zu bevorzugen.

Praktische Beispiele für Mausbewegungsereignisse

Diese Beispiele zeigen, wie Mausbewegungsereignisse implementiert werden können, um die Benutzererfahrung durch interaktive Elemente zu verbessern.

Beispiel 1: Verwendung von Mouseover und Mouseout

Dieses Beispiel zeigt, wie die Hintergrundfarbe einer Box geändert werden kann, wenn der Mauszeiger sie betritt und verlässt, einschließlich ihrer Kind-Elemente.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Mouseover and Mouseout Example</title>
    <style>
        #box {
            width: 200px;
            height: 200px;
            background-color: lightblue;
        }
        #innerBox {
            width: 100px;
            height: 100px;
            background-color: lightcoral;
            margin: 50px;
        }
    </style>
</head>
<body>
<div id="box">
    Hover over me!
    <div id="innerBox"></div>
</div>

<script>
    document.getElementById('box').addEventListener('mouseover', function() {
        this.style.backgroundColor = 'cyan';
    });
    document.getElementById('box').addEventListener('mouseout', function() {
        this.style.backgroundColor = 'lightblue';
    });
</script>
</body>
</html>

Erläuterung:

  • Das Ereignis mouseover ändert die Hintergrundfarbe der Box auf Cyan, auch wenn über die innere Box gehovt wird.
  • Das Ereignis mouseout setzt die Hintergrundfarbe zurück, wenn die Maus die Box verlässt, wobei die innere Box ebenfalls berücksichtigt wird.

Beispiel 2: Verwendung von Mouseenter und Mouseleave

Dieses Beispiel verbessert die Benutzerinteraktion, indem es zeigt, wie mouseenter und mouseleave für eine gezieltere Reaktion verwendet werden können, ohne Kind-Elemente zu beeinflussen.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Mouseenter and Mouseleave Visual Example</title>
    <style>
        #parent {
            width: 400px;
            height: 300px;
            background-color: lightblue; /* Initial background color */
            padding: 20px;
            box-sizing: border-box;
            position: relative;
            display: flex;
            justify-content: space-around;
            align-items: center;
            transition: background-color 0.3s ease;
        }
        .child {
            width: 90px;
            height: 90px;
            background-color: lightsalmon;
            display: flex;
            justify-content: center;
            align-items: center;
            transition: background-color 0.3s ease;
        }
        #feedback {
            position: fixed;
            bottom: 10px;
            left: 10px;
            background: white;
            padding: 10px;
            border: 1px solid #ccc;
            font-family: Arial, sans-serif;
        }
    </style>
</head>
<body>
<div id="parent">
    Parent Element
    <div class="child">Child 1</div>
    <div class="child">Child 2</div>
    <div class="child">Child 3</div>
</div>
<div id="feedback">Hover over elements to see interactions.</div>

<script>
    const parent = document.getElementById('parent');
    const children = document.querySelectorAll('.child');
    const feedback = document.getElementById('feedback');

    parent.addEventListener('mouseenter', function() {
        parent.style.backgroundColor = 'cyan'; // Highlight the parent on mouse enter
        feedback.textContent = 'Mouse entered the parent element';
    });

    parent.addEventListener('mouseleave', function() {
        parent.style.backgroundColor = 'lightblue'; // Revert color on mouse leave
        feedback.textContent = 'Mouse left the parent element';
    });

    // Update feedback for child interactions
    children.forEach(child => {
        child.addEventListener('mouseenter', function() {
            feedback.textContent = `Mouse entered ${this.textContent}`;
            this.style.backgroundColor = '#ffcccb'; // Highlight child on mouse enter
        });
        child.addEventListener('mouseleave', function() {
            feedback.textContent = `Mouse left ${this.textContent}`;
            this.style.backgroundColor = 'lightsalmon'; // Revert child color on mouse leave
        });
    });
</script>
</body>
</html>

Dieses Beispiel verdeutlicht klar, wie mouseenter- und mouseleave-Ereignisse gezielt ausgelöst werden und nicht bubbles, was eindeutige und isolierte Interaktionen mit verschachtelten Elementen ermöglicht.

Beispiel 3: mouseleave mit relatedTarget nachahmen

Manchmal benötigt man Bubbling (um einen einzelnen delegierten Listener verwenden zu können) und das saubere „nur wenn der Zeiger das Element wirklich verlässt"-Verhalten. Beides lässt sich kombinieren, indem man auf das bubbelnde mouseout hört und Übergänge zu Nachfahren mithilfe von relatedTarget ignoriert. Die Logik entspricht der oben gezeigten, ausgedrückt als kleiner wiederverwendbarer Helfer:

function reallyLeft(event, element) {
  // True only when the pointer moves to something OUTSIDE `element`.
  const to = event.relatedTarget;
  return to === null || !element.contains(to);
}

// Demonstrate without a browser: simulate a mouseout whose related
// target is a child (should be ignored) and one to an outside node.
const card = { contains: (node) => node === 'child' };

console.log(reallyLeft({ relatedTarget: 'child' }, card));   // false (still inside)
console.log(reallyLeft({ relatedTarget: 'outside' }, card)); // true  (really left)
console.log(reallyLeft({ relatedTarget: null }, card));      // true  (left the window)

Dieses Muster ist die Grundlage dafür, wie Bibliotheken zuverlässige Hover-Menüs implementieren: Ein einzelner bubbelnder Listener auf dem Menü-Root, aber das Menü wird nur eingeklappt, wenn der Zeiger den gesamten Teilbaum verlässt.

Fazit

Mausbewegungsereignisse ermöglichen es Ihnen, nuancierte, reaktionsfähige Interaktionen rund um den Zeiger des Benutzers zu erstellen. Das Wichtigste dabei ist die Paarung:

  • Verwenden Sie mouseenter/mouseleave für einen sauberen, elementbezogenen Hover-Zustand — sie werden einmal ausgelöst und ignorieren Kind-Elemente.
  • Verwenden Sie mouseover/mouseout wenn Sie Bubbling für die Event-Delegation benötigen, und nutzen Sie relatedTarget, um Übergänge zu Nachfahren herauszufiltern.

Zur Vertiefung empfiehlt sich die Lektüre der Grundlagen zu Mausereignissen für Klicks und Schaltflächen sowie die Einführung in Browser-Ereignisse für einen allgemeinen Überblick über die Ereignisverkabelung.

Übungen

Übung
Was sind die wesentlichen Unterschiede zwischen den Ereignissen Mouseover/Mouseout und Mouseenter/Mouseleave in JavaScript?
Was sind die wesentlichen Unterschiede zwischen den Ereignissen Mouseover/Mouseout und Mouseenter/Mouseleave in JavaScript?
Was this page helpful?