diff --git a/2-ui/2-events/01-introduction-browser-events/article.md b/2-ui/2-events/01-introduction-browser-events/article.md index 64f06497..332d1579 100644 --- a/2-ui/2-events/01-introduction-browser-events/article.md +++ b/2-ui/2-events/01-introduction-browser-events/article.md @@ -216,7 +216,7 @@ Web-standard developers understood that long ago and suggested an alternative wa The syntax to add a handler: ```js -element.addEventListener(event, handler[, phase]); +element.addEventListener(event, handler[, options]); ``` `event` @@ -225,15 +225,17 @@ element.addEventListener(event, handler[, phase]); `handler` : The handler function. -`phase` -: An optional argument, the "phase" for the handler to work. To be covered later. Usually we don't use it. +`options` +: An additional optional object with properties: + - `once`: if `true`, then the listener is automatically removed after it triggers. + - `capture`: the phrase where to handle the event, to be covered later in the chapter . For historical reasons, `options` can also be `false/true`, that's the same as `{capture: false/true}`. + - `passive`: if `true`, then the handler will not `preventDefault()`, we'll cover that later in . + To remove the handler, use `removeEventListener`: - ```js -// exactly the same arguments as addEventListener -element.removeEventListener(event, handler[, phase]); +element.removeEventListener(event, handler[, options]); ``` ````warn header="Removal requires the same function" diff --git a/2-ui/2-events/02-bubbling-and-capturing/article.md b/2-ui/2-events/02-bubbling-and-capturing/article.md index 191b2739..d489b710 100644 --- a/2-ui/2-events/02-bubbling-and-capturing/article.md +++ b/2-ui/2-events/02-bubbling-and-capturing/article.md @@ -136,9 +136,9 @@ That is: for a click on `` the event first goes through the ancestors chain Handlers added using `on`-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. -To catch an event on the capturing phase, we need to set the 3rd argument of `addEventListener` to `true`. +To catch an event on the capturing phase, we need to set the event options of `addEventListener` to `{capture: true}` (or just `true`). -There are two possible values for that optional last argument: +There are two possible values `capture` option: - If it's `false` (default), then the handler is set on the bubbling phase. - If it's `true`, then the handler is set on the capturing phase. @@ -182,12 +182,16 @@ Please note that `P` shows up two times: at the end of capturing and at the star 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. +```smart header="To remove the handler, `removeEventListener` needs the same phase" +If we `addEventListener(..., true)`, then we should mention the same phase in `removeEventListener(..., true)` to correctly remove the handler. +``` + ## Summary The event handling process: - When an event happens -- the most nested element where it happens gets labeled as the "target element" (`event.target`). -- Then the event first moves from the document root down to the `event.target`, calling handlers assigned with `addEventListener(...., true)` on the way. +- Then the event first moves from the document root down to the `event.target`, calling handlers assigned with `addEventListener(...., true)` on the way (`true` is a shorthand for `{capture: true}`). - Then the event moves from `event.target` up to the root, calling handlers assigned using `on` and `addEventListener` without the 3rd argument or with the 3rd argument `false`. Each handler can access `event` object properties: diff --git a/2-ui/2-events/04-default-browser-action/article.md b/2-ui/2-events/04-default-browser-action/article.md index b2889132..44355de0 100644 --- a/2-ui/2-events/04-default-browser-action/article.md +++ b/2-ui/2-events/04-default-browser-action/article.md @@ -93,6 +93,20 @@ But if you click the second one, there's no focus. That's because the browser action is canceled on `mousedown`. The focusing is still possible if we use another way to enter the input. For instance, the `key:Tab` key to switch from the 1st input into the 2nd. But not with the mouse click any more. +## The "passive" handler option + +The optional `passive: true` option of `addEventListener` signals the browser that the handler is not going to call `preventDefault()`. + +Why that may be needed? + +There are some events like `touchmove` on mobile devices (when the user moves their finger across the screen), that cause scrolling by default, but that scrolling can be prevented using `preventDefault()` in the handler. + +So when the browser detects such event, it has first to process all handlers, and then if `preventDefault` is not called anywhere, it can proceed with scrolling. That may cause unnecessary delays and "jitters" in the UI. + +The `passive: true` options tells the browser that the handler is not going to cancel scrolling. Then browser scrolls immediately providing a maximally fluent experience, and the event is handled by the way. + +For some browsers (Firefox, Chrome), `passive` is `true` by default for `touchstart` and `touchmove` events. + ## event.defaultPrevented @@ -215,6 +229,8 @@ All the default actions can be prevented if we want to handle the event exclusiv To prevent a default action -- use either `event.preventDefault()` or `return false`. The second method works only for handlers assigned with `on`. +The `passive: true` option of `addEventListener` tells the browser that the action is not going to be prevented. That's useful for some mobile events, like `touchstart` and `touchmove`, to tell the browser that it should not wait for all handlers to finish before scrolling. + If the default action was prevented, the value of `event.defaultPrevented` becomes `true`, otherwise it's `false`. ```warn header="Stay semantic, don't abuse"