Moving the mouse mouseover out, mouseenter leave
JavaScript Moving the mouse: mouseover/out, mouseenter/leave
In this chapter, we are going to explore what comes about when the mouse moves between elements. Let’s start to dive into details about what mouseover, mouseout, mouseenter and mouseleave events are and how they operate. (在本章中,我们将探讨当鼠标在元素之间移动时会发生什么。让我们开始深入了解什么是mouseover、mouseout、mouseenter和mouseleave事件及其操作方式。)
Events mouseover/mouseout, relatedTarget
Events mouseover/mouseout, relatedTarget (事件mouseover/mouseout , relatedTarget)
The mouseover event takes place when the pointer of the mouse comes over an element. On the contrary, the mouseout event occurs when it leaves. (当鼠标指针指向某个元素时,会发生mouseover事件。相反, mouseout事件在离开时发生。)
These events are considered specific, as they include the relatedTarget property. The relatedTarget property complements target. After a mouse leaves an element for another, one of them transforms into the target, the other one- into the relatedTarget. (这些事件被认为是特定的,因为它们包括relatedTarget属性。relatedTarget属性补充了target。鼠标将一个元素留给另一个元素后,其中一个转换为目标,另一个转换为relatedTarget。)
So, for mouseover:
the element where the mouse came over is the event.target . (-鼠标出现的元素是event.target。)
the element from which the mouse came is the event.relatedTarget.(relatedTarget → target) (-鼠标来自的元素是event.relatedTarget。( relatedTarget → target ))
For mouseout, we have the opposite situation:
the element that the mouse left is the event.target . (-鼠标左侧的元素是event.target。)
the new under-the-point element the mouse left for is the event.relatedTarget (target → relatedTarget. (-鼠标留给的新点下元素是event.relatedTarget ( target → relatedTarget。)
Please, note that relatedTarget can be null. (请注意, relatedTarget可以为null。)
It can be considered typical and means that the mouse didn’t come from another element but out of the window. So, it would be best if you kept that fact in mind while using event.relatedTarget in your code. If you try accessing event.relatedTarget.tagName an error will occur. (它可以被认为是典型的,意味着鼠标不是来自其他元素,而是来自窗外。因此,最好在代码中使用event.relatedTarget时记住这一事实。如果尝试访问event.relatedTarget.tagName ,将发生错误。)
Skipping Elements
Skipping Elements (跳过元素)
The mouseover element gets activated when the mouse moves. But it doesn’t mean that each pixel will lead to an event. Time to time the mouse position is checked by the browser. As a result, whenever a change is noticed, events are triggered. It also means that if the visitor moves the mouse very fast, several DOM-elements might be skipped, like this:
In the picture above, if the mouse moves too fast from “FROM” to “TO”, then the intermediate <div> elements might be skipped. The mouseout event will trigger on “FROM” and then directly on “TO”. In practice, it is quite handy because there may be too many intermediate elements that you don’t wish to go through.
Please, take into consideration the mouse pointer doesn’t always go through all the elements on the way. That is possible that the pointer jumps right inside the middle of the page from the outside of the window. In a case like this, relatedTarget is null, as it’s not known where exactly it came from, like here:
You can easily check it out here:
<!DOCTYPE html>
<html>
<head>
<title>Title of the Document</title>
<style>
#parent {
background: #008000;
width: 200px;
height: 140px;
position: relative;
}
#child {
background: #0000FF;
width: 50%;
height: 50%;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
textarea {
height: 200px;
width: 500px;
display: block;
}
</style>
</head>
<body>
<div id="parent">
Parent
(上一级)
<div id="child">Child</div>
</div>
<textarea id="text"></textarea>
<input onclick="clearText()" value="Clear" type="button">
<script>
let parent = document.getElementById('parent');
parent.onmouseover = parent.onmouseout = parent.onmousemove = handler;
function handler(event) {
let type = event.type;
while(type < 11) type += ' ';
log(type + " target=" + event.target.id)
(log (type + "target =" + event.target.id))
return false;
}
function clearText() {
text.value = "";
lastMessage = "";
}
let lastMessageTime = 0;
let lastMessage = "";
let repeatCounter = 1;
function log(message) {
if(lastMessageTime == 0) lastMessageTime = new Date();
let time = new Date();
if(time - lastMessageTime > 500) {
message = '------------------------------\n' + message;
}
if(message === lastMessage) {
repeatCounter++;
if(repeatCounter == 2) {
text.value = text.value.trim() + ' x 2\n';
} else {
text.value = text.value.slice(0, text.value.lastIndexOf('x') + 1) + repeatCounter + "\n";
}
} else {
repeatCounter = 1;
text.value += message + "\n";
}
text.scrollTop = text.scrollHeight;
lastMessageTime = time;
lastMessage = message;
}
</script>
</body>
</html>
An important note: One thing is sure that if the pointer has entered an element (mouseover), the mouseout will also be implemented.
Mouseout when Leaving for a Child
Mouseout when Leaving for a Child (为孩子离开时鼠标略过)
Another important mouseout feature is that it triggers at the time the pointer moves from an element to its descendant. In other words, when it moves from #parent to #child, like in the HTML example below:
<div id="parent">
<div id="child">...</div>
</div>
When you are on #parent, then move the pointer to the #child, you will get mouseout on the #parent. That can seem strange at first sight but it has an explanation. In pursuance of the browser logic, the cursor of the mouse can be over a single element at any time. So, in case it goes to another element, it leaves the former one.
Another important detail of the event proceeding is the following: the mouseover event on a descendant can bubble up, and if the #parent has a mouseover handler, it will trigger.
Moving the mouse from #parent to #child will bring two events on #parent, like here:
mouseout [target: parent] (left the parent), after mouseover [target: child] (reached the child, bubbled).
<!DOCTYPE html>
<html>
<head>
<title>Title of the Document</title>
<style>
#parent {
background: #008000;
width: 200px;
height: 140px;
position: relative;
}
#child {
background: #0000FF;
width: 50%;
height: 50%;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
textarea {
height: 200px;
width: 500px;
display: block;
}
</style>
</head>
<body>
<div id="parent" onmouseover="mouselog(event)" onmouseout="mouselog(event)">
Parent
(上一级)
<div id="child">Child</div>
</div>
<textarea id="text"></textarea>
<input type="button" onclick="text.value=''" value="Clear">
<script>
function mouselog(event) {
let d = new Date();
text.value += `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()} | ${event.type} [target: ${event.target.id}]\n`.replace(/(:|^)(\d\D)/, '$10$2');
text.scrollTop = text.scrollHeight;
}
</script>
</body>
</html>
So, at the moment the pointer moves from #parent element to #child, on the parent element, mouseover, and mouseout trigger, as follows:
parent.onmouseout = function (event) {
/* event.target: parent element */
};
parent.onmouseover = function (event) {
/* event.target: child element */
};
Events mouseenter and mouseleave
Events mouseenter and mouseleave (事件mouseenter和mouseleave)
Other events, such as mouseenter and mouseleave are similar to mouseover and mouseout. They also trigger at the moment the mouse pointer enters or leaves the element. (其他事件,如mouseenter和mouseleave类似于mouseover和mouseout。它们也会在鼠标指针进入或离开元素时触发。)
But, they are not the same as the events above. At least two essential differences can be pointed out:
The transitions inside the element are not counted. (-元素内部的过渡不计算在内。)
These events (mouseenter, mouseleave) never bubble. (-这些事件( mouseenter、mouseleave )永远不会冒泡。)
These events are simpler than the previous ones. (这些活动比以前的活动更简单。)
At the moment the pointer enters an element, the mouseenter event triggers. The specific location of the pointer or its descendant doesn’t matter. As for the mouseleave, it triggers when the pointer leaves an element. (当指针进入元素时, mouseenter事件触发。指针或其后代的具体位置无关紧要。至于鼠标左键,它会在指针离开元素时触发。)
So, the only generated events are the ones connected to moving to moving the pointer in and out of the top element. Nothing will happen in case the pointer moves to the child and back. Any transitions between descendants will be dismissed:
<!DOCTYPE html>
<html>
<head>
<title>Title of the Document</title>
<style>
#parent {
background: #008000;
width: 200px;
height: 140px;
position: relative;
}
#child {
background: #0000FF;
width: 50%;
height: 50%;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
textarea {
height: 200px;
width: 500px;
display: block;
}
</style>
</head>
<body>
<div id="parent" onmouseenter="mouselog(event)" onmouseleave="mouselog(event)">
Parent
(上一级)
<div id="child">Child</div>
</div>
<textarea id="text"></textarea>
<input type="button" onclick="text.value=''" value="Clear">
<script>
function mouselog(event) {
let d = new Date();
text.value += `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()} | ${event.type} [target: ${event.target.id}]\n`.replace(/(:|^)(\d\D)/, '$10$2');
text.scrollTop = text.scrollHeight;
}
</script>
</body>
</html>
Summary
Summary (概要)
In this chapter, we dived deeper into the events in JavaScript. We explored the events such as mousemove, mouseover, mouseout, mouseenter and mouseleave. (在本章中,我们深入探讨了JavaScript中的事件。我们探讨了mousemove、mouseover、mouseout、mouseenter和mouseleave等事件。)
The following things are especially handy:
A fast mouse move skips intermediate elements. (-鼠标快速移动可跳过中间元素。)
The mouseover/out and mouseenter/leave events include an additional useful property called relatedTarget. (- mouseover/out和mouseenter/leave事件包括一个名为relatedTarget的额外有用属性。)
The mouseover/mouseout events can trigger even when moving from the parent element to a child. Your browser assumes that the mouse may only be over a single element at one time. (即使从父元素移动到子元素, mouseover/mouseout事件也可能触发。您的浏览器假定鼠标一次只能位于一个元素上方。)
In that aspect, the mouseenter/mouseleave events differ from the events above. They can trigger only when the mouse moves in and out of the element as a whole. Another significant thing to remember: the mouseenter/mouseleave events don’t bubble.