Event Flow: capture, target, and bubbling
An event has three phases to its life cycle: capture, target, and bubbling.
Capture Phase
The event capture phase is shown in the following image:
Bubble Phase
The event bubble phase is shown in the following image:
Target Phase
When the capture phase has finished, the browser triggers any listeners for the event type.
Calling the stopPropagation or stopImmediatePropagation functions during the target phase stops the flow of the event and the bubble phase won't be performed.
The following code shows the event capture phase:
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<style type="text/css">
p {
background: gray;
color: white;
padding: 10px;
margin: 5px;
border: thin solid black
}
span {
background: white;
color: black;
padding: 2px;
cursor: default;
}
</style>
</head>
<body>
<p id="block1">
<span id="mySpan">This is a span. </span>
</p>
<script type="text/javascript">
var mySpan = document.getElementById("mySpan");
var textblock = document.getElementById("block1");
mySpan.addEventListener("mouseover", handleMouseEvent);
mySpan.addEventListener("mouseout", handleMouseEvent);
textblock.addEventListener("mouseover", handleDescendantEvent, true);
textblock.addEventListener("mouseout", handleDescendantEvent, true);
function handleDescendantEvent(e) {
if (e.type == "mouseover" && e.eventPhase == Event.CAPTURING_PHASE) {
e.target.style.border = "thin solid red";
e.currentTarget.style.border = "thick double black";
} else if (e.type == "mouseout" && e.eventPhase == Event.CAPTURING_PHASE) {
e.target.style.removeProperty("border");
e.currentTarget.style.removeProperty("border");
}
}
function handleMouseEvent(e) {
if (e.type == "mouseover") {
e.target.style.background = 'white';
e.target.style.color = 'black';
} else {
e.target.style.removeProperty('color');
e.target.style.removeProperty('background');
}
}
</script>
</body>
</html>
A parent element event handler can stop flow of the event down toward the target by calling the stopPropagation or stopImmediatePropagation.
stopPropagation ensures that all of the event listeners registered for the current element will be invoked. stopImmediatePropagation ignores any untriggered listeners.
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<style type="text/css">
span {
background: white;
color: black;
padding: 2px;
cursor: default;
}
</style>
</head>
<body>
<p id="block1">
<span id="mySpan">This is a span. </span>
</p>
<script type="text/javascript">
var mySpan = document.getElementById("mySpan");
var textblock = document.getElementById("block1");
mySpan.addEventListener("mouseover", handleMouseEvent);
mySpan.addEventListener("mouseout", handleMouseEvent);
textblock.addEventListener("mouseover", handleDescendantEvent, true);
textblock.addEventListener("mouseout", handleDescendantEvent, true);
function handleDescendantEvent(e) {
if (e.type == "mouseover" && e.eventPhase == Event.CAPTURING_PHASE) {
e.target.style.border = "thick solid red";
e.currentTarget.style.border = "thick double black";
} else if (e.type == "mouseout" && e.eventPhase == Event.CAPTURING_PHASE) {
e.target.style.removeProperty("border");
e.currentTarget.style.removeProperty("border");
}
e.stopPropagation();
}
function handleMouseEvent(e) {
if (e.type == "mouseover") {
e.target.style.background = 'white';
e.target.style.color = 'black';
} else {
e.target.style.removeProperty('color');
e.target.style.removeProperty('background');
}
}
</script>
</body>
</html>
The following code shows the event bubble phase:
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<style type="text/css">
span {
background: white;
color: black;
padding: 2px;
cursor: default;
}
</style>
</head>
<body>
<p id="block1">
<span id="mySpan">This is a span. </span>
</p>
<script type="text/javascript">
var mySpan = document.getElementById("mySpan");
var textblock = document.getElementById("block1");
mySpan.addEventListener("mouseover", handleMouseEvent);
mySpan.addEventListener("mouseout", handleMouseEvent);
textblock.addEventListener("mouseover", handleDescendantEvent, true);
textblock.addEventListener("mouseout", handleDescendantEvent, true);
textblock.addEventListener("mouseover", handleBubbleMouseEvent, false);
textblock.addEventListener("mouseout", handleBubbleMouseEvent, false);
function handleBubbleMouseEvent(e) {
if (e.type == "mouseover" && e.eventPhase == Event.BUBBLING_PHASE) {
e.target.style.textTransform = "uppercase";
} else if (e.type == "mouseout"
&& e.eventPhase == Event.BUBBLING_PHASE) {
e.target.style.textTransform = "none";
}
}
function handleDescendantEvent(e) {
if (e.type == "mouseover" && e.eventPhase == Event.CAPTURING_PHASE) {
e.target.style.border = "thn solid red";
e.currentTarget.style.background = "blue";
} else if (e.type == "mouseout"
&& e.eventPhase == Event.CAPTURING_PHASE) {
e.target.style.removeProperty("border");
e.currentTarget.style.removeProperty("border");
}
}
function handleMouseEvent(e) {
if (e.type == "mouseover") {
e.target.style.background = 'black';
e.target.style.color = 'white';
} else {
e.target.style.removeProperty('color');
e.target.style.removeProperty('background');
}
}
</script>
</body>
</html>
Not all events support bubbling. Event bubbles property tells if the event supports bubble. It returns a true/false value.
<!DOCTYPE HTML>
<html>
<head>
<title>Example</title>
<style type="text/css">
span {
background: white;
color: black;
padding: 2px;
cursor: default;
}
</style>
</head>
<body>
<p id="block1">
<span id="mySpan">This is a span. </span>
</p>
<script type="text/javascript">
var mySpan = document.getElementById("mySpan");
var textblock = document.getElementById("block1");
textblock.addEventListener("mouseover", handleBubbleMouseEvent, false);
textblock.addEventListener("mouseout", handleBubbleMouseEvent, false);
function handleBubbleMouseEvent(e) {
document.writeln(e.bubbles);
}
</script>
</body>
</html>
JavaScript Book
DOM
- The DOM Events
- Event Flow: capture, target, and bubbling
- eventPhase
- preventDefault: Cancellable Events
- Events Type
- Event Target