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.
| Ereignis | Wird ausgelöst, wenn der Zeiger… | Bubbling? | Erneut bei Kind-Elementen? |
|---|---|---|---|
mouseover | das Element oder einen Nachfahren betritt | Ja | Ja |
mouseout | das Element oder einen Nachfahren verlässt | Ja | Ja |
mouseenter | die eigene Grenze des Elements betritt | Nein | Nein |
mouseleave | die eigene Grenze des Elements verlässt | Nein | Nein |
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 zumouseover— 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 wiemouseover, 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, undmouseover/mouseoutnur 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/mouseenteristrelatedTargetdas Element, von dem der Zeiger kam. - Bei
mouseout/mouseleaveistrelatedTargetdas 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
mouseoutsetzt 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/mouseleavefür einen sauberen, elementbezogenen Hover-Zustand — sie werden einmal ausgelöst und ignorieren Kind-Elemente. - Verwenden Sie
mouseover/mouseoutwenn Sie Bubbling für die Event-Delegation benötigen, und nutzen SierelatedTarget, 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.