Skip to content

Commit 98ea21c

Browse files
authored
Merge pull request #347 from odsantos/update-en-bubbling-capturing
Update "Bubbling and capturing" article
2 parents c9c0fa6 + 72f19fd commit 98ea21c

File tree

1 file changed

+33
-16
lines changed

1 file changed

+33
-16
lines changed

2-ui/2-events/02-bubbling-and-capturing/article.md

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ Check it out:
7575

7676
[codetabs height=220 src="bubble-target"]
7777

78-
It's possible that `event.target` equals `this` -- when the click is made directly on the `<form>` element.
78+
It's possible that `event.target` could equal `this` -- it happens when the click is made directly on the `<form>` element.
7979

8080
## Stopping bubbling
8181

@@ -110,7 +110,7 @@ For instance:
110110
111111
1. We create a nested menu. Each submenu handles clicks on its elements and calls `stopPropagation` so that the outer menu won't trigger.
112112
2. Later we decide to catch clicks on the whole window, to track users' behavior (where people click). Some analytic systems do that. Usually the code uses `document.addEventListener('click'…)` to catch all clicks.
113-
3. Our analytic won't work over the area where clicks are stopped by `stopPropagation`. We've got a "dead zone".
113+
3. Our analytic won't work over the area where clicks are stopped by `stopPropagation`. Sadly, we've got a "dead zone".
114114
115115
There's usually no real need to prevent the bubbling. A task that seemingly requires that may be solved by other means. One of them is to use custom events, we'll cover them later. Also we can write our data into the `event` object in one handler and read it in another one, so we can pass to handlers on parents information about the processing below.
116116
```
@@ -120,26 +120,27 @@ There's usually no real need to prevent the bubbling. A task that seemingly requ
120120

121121
There's another phase of event processing called "capturing". It is rarely used in real code, but sometimes can be useful.
122122

123-
The standard [DOM Events](http://www.w3.org/TR/DOM-Level-3-Events/) describes 3 phases of event propagation:
123+
The standard [DOM Events](https://www.w3.org/TR/DOM-Level-3-Events/) describes 3 phases of event propagation:
124124

125125
1. Capturing phase -- the event goes down to the element.
126126
2. Target phase -- the event reached the target element.
127127
3. Bubbling phase -- the event bubbles up from the element.
128128

129-
Here's the picture of a click on `<td>` inside a table, taken from the specification:
129+
Here's the picture, taken from the specification, of the capturing `(1)`, target `(2)` and bubbling `(3)` phases for a click event on a `<td>` inside a table:
130130

131131
![](eventflow.svg)
132132

133-
That is: for a click on `<td>` the event first goes through the ancestors chain down to the element (capturing), then it reaches the target, and then it goes up (bubbles), calling handlers on its way.
133+
That is: for a click on `<td>` the event first goes through the ancestors chain down to the element (capturing phase), then it reaches the target and triggers there (target phase), and then it goes up (bubbling phase), calling handlers on its way.
134134

135-
**Before we only talked about bubbling, because the capturing phase is rarely used. Normally it is invisible to us.**
135+
Until now, we only talked about bubbling, because the capturing phase is rarely used.
136136

137-
Handlers added using `on<event>`-property or using HTML attributes or using `addEventListener(event, handler)` don't know anything about capturing, they only run on the 2nd and 3rd phases.
137+
In fact, the capturing phase was invisible for us, because handlers added using `on<event>`-property or using HTML attributes or using two-argument `addEventListener(event, handler)` don't know anything about capturing, they only run on the 2nd and 3rd phases.
138138

139139
To catch an event on the capturing phase, we need to set the handler `capture` option to `true`:
140140

141141
```js
142142
elem.addEventListener(..., {capture: true})
143+
143144
// or, just "true" is an alias to {capture: true}
144145
elem.addEventListener(..., true)
145146
```
@@ -149,11 +150,10 @@ There are two possible values of the `capture` option:
149150
- If it's `false` (default), then the handler is set on the bubbling phase.
150151
- If it's `true`, then the handler is set on the capturing phase.
151152

152-
Note that while formally there are 3 phases, the 2nd phase ("target phase": the event reached the element) is not handled separately: handlers on both capturing and bubbling phases trigger at that phase.
153153

154-
If one puts capturing and bubbling handlers on the target element, the capture handler triggers last in the capturing phase and the bubble handler triggers first in the bubbling phase.
154+
Note that while formally there are 3 phases, the 2nd phase ("target phase": the event reached the element) is not handled separately: handlers on both capturing and bubbling phases trigger at that phase.
155155

156-
Let's see it in action:
156+
Let's see both capturing and bubbling in action:
157157

158158
```html run autorun height=140 edit
159159
<style>
@@ -181,19 +181,36 @@ The code sets click handlers on *every* element in the document to see which one
181181

182182
If you click on `<p>`, then the sequence is:
183183

184-
1. `HTML` -> `BODY` -> `FORM` -> `DIV` (capturing phase, the first listener):
185-
2. `P` (target phase, triggers two times, as we've set two listeners: capturing and bubbling)
186-
3. `DIV` -> `FORM` -> `BODY` -> `HTML` (bubbling phase, the second listener).
184+
1. `HTML` -> `BODY` -> `FORM` -> `DIV -> P` (capturing phase, the first listener):
185+
2. `P` -> `DIV` -> `FORM` -> `BODY` -> `HTML` (bubbling phase, the second listener).
186+
187+
Please note, the `P` shows up twice, because we've set two listeners: capturing and bubbling. The target triggers at the end of the first and at the beginning of the second phase.
187188

188189
There's a property `event.eventPhase` that tells us the number of the phase on which the event was caught. But it's rarely used, because we usually know it in the handler.
189190

190191
```smart header="To remove the handler, `removeEventListener` needs the same phase"
191192
If we `addEventListener(..., true)`, then we should mention the same phase in `removeEventListener(..., true)` to correctly remove the handler.
192193
```
193194
195+
````smart header="Listeners on the same element and same phase run in their set order"
196+
If we have multiple event handlers on the same phase, assigned to the same element with `addEventListener`, they run in the same order as they are created:
197+
198+
```js
199+
elem.addEventListener("click", e => alert(1)); // guaranteed to trigger first
200+
elem.addEventListener("click", e => alert(2));
201+
```
202+
````
203+
204+
```smart header="The `event.stopPropagation()` during the capturing also prevents the bubbling"
205+
The `event.stopPropagation()` method and its sibling `event.stopImmediatePropagation()` can also be called on the capturing phase. Then not only the futher capturing is stopped, but the bubbling as well.
206+
207+
In other words, normally the event goes first down ("capturing") and then up ("bubbling"). But if `event.stopPropagation()` is called during the capturing phase, then the event travel stops, no bubbling will occur.
208+
```
209+
210+
194211
## Summary
195212
196-
The event handling process:
213+
When an event happens -- the most nested element where it happens gets labeled as the "target element" (`event.target`).
197214
198215
- Then the event moves down from the document root to `event.target`, calling handlers assigned with `addEventListener(..., true)` on the way (`true` is a shorthand for `{capture: true}`).
199216
- Then handlers are called on the target element itself.
@@ -203,11 +220,11 @@ Each handler can access `event` object properties:
203220
204221
- `event.target` -- the deepest element that originated the event.
205222
- `event.currentTarget` (=`this`) -- the current element that handles the event (the one that has the handler on it)
206-
- `event.eventPhase` -- the current phase (capturing=1, bubbling=3).
223+
- `event.eventPhase` -- the current phase (capturing=1, target=2, bubbling=3).
207224
208225
Any event handler can stop the event by calling `event.stopPropagation()`, but that's not recommended, because we can't really be sure we won't need it above, maybe for completely different things.
209226
210-
The capturing phase is used very rarely, usually we handle events on bubbling. And there's a logic behind that.
227+
The capturing phase is used very rarely, usually we handle events on bubbling. And there's a logical explanation for that.
211228
212229
In real world, when an accident happens, local authorities react first. They know best the area where it happened. Then higher-level authorities if needed.
213230

0 commit comments

Comments
 (0)