-
Notifications
You must be signed in to change notification settings - Fork 687
Добавляет ответ на вопрос к собеседованию про event-bubbling #5879
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
kutepoff45
wants to merge
6
commits into
doka-guide:main
Choose a base branch
from
kutepoff45:event-bubbling
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
2323c9b
Добавляет ответ на вопрос к собеседованию про event-bubbling
fcdd683
Исправляет текст ответа согласно руководству по стилю
e5ad9cc
Исправляет текст ответа после ревью
ca33e41
Исправляет текст ответа после ревью
kutepoff45 222d707
Добавляет нового участника в раздел people
kutepoff45 0e65943
Исправляет текст ответа после ревью
kutepoff45 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
**Всплытие события (event bubbling)** — это механизм [`Событийной модели`](/js/events/) браузера, при котором событие, произошедшее на вложенном элементе, последовательно «поднимается» вверх по дереву [`DOM`](/js/dom/) через его предков, пока не достигнет объекта document (а в конце — window). | ||
|
||
В [`Событийной модели`](/js/events/) есть ещё и фаза захвата (capturing) — она предшествует всплытию и идёт в обратном направлении: сверху вниз, от window к целевому элементу. По умолчанию обработчики срабатывают именно на фазе всплытия, поэтому чаще всего говорят именно о ней. | ||
|
||
Проще говоря: если кликнули на кнопку внутри [`<div>`](/html/div/), сначала обработчик сработает на кнопке, затем на [`<div>`](/html/div/), затем на [`<body>`](/html/body/), и так далее (если на всех перечисленных элементах присутствует обработчик события [`click`](/js/element-click/)). | ||
|
||
Рассмотрим пример. Наш контейнер с кнопкой: | ||
|
||
```html | ||
<div id="container"> | ||
<button>Нажми на меня</button> | ||
</div> | ||
``` | ||
|
||
Добавим обработку клика по кнопке: | ||
|
||
```js | ||
const container = document.getElementById('container') | ||
|
||
container.addEventListener('click', containerClick) | ||
|
||
function containerClick(event) { | ||
console.log(`Зарегистрировано событие на контейнере ${event.currentTarget.tagName}`) | ||
} | ||
``` | ||
|
||
При клике по кнопке вызывается слушатель события, который был установлен на контейнере. Это происходит благодаря тому, что событие [`click`](/js/element-click/) всплывает - сначала вызывается слушатель на кнопке (но там слушателя нет), потом на контейнере (там слушатель есть, он вызывает `console.log()`). | ||
|
||
Рассмотрим другой пример. Обернём наш контейнер с кнопкой ещё одним элементом [`<body>`](/html/body/): | ||
|
||
```html | ||
<html> | ||
<body> | ||
<div id="container"> | ||
<button>Нажми на меня</button> | ||
</div> | ||
</body> | ||
</html> | ||
``` | ||
|
||
Добавим обработку клика на все три элемента: | ||
|
||
```js | ||
const button = document.querySelector('button') | ||
const container = document.getElementById('container') | ||
const body = document.querySelector('body') | ||
|
||
button.addEventListener('click', handleClick) | ||
container.addEventListener('click', handleClick) | ||
body.addEventListener('click', handleClick) | ||
|
||
function handleClick(event) { | ||
console.log(`Зарегистрировано событие на элементе ${event.currentTarget.tagName}`) | ||
} | ||
``` | ||
|
||
При клике на элемент срабатывает всплытие, и функция `handleClick()` вызывается соответствующее количество раз. | ||
1. Клик на button: | ||
|
||
``` | ||
Зарегистрировано событие на элементе BUTTON | ||
Зарегистрировано событие на элементе DIV | ||
Зарегистрировано событие на элементе BODY | ||
``` | ||
2. Клик на container: | ||
|
||
``` | ||
Зарегистрировано событие на элементе DIV | ||
Зарегистрировано событие на элементе BODY | ||
``` | ||
3. Клик на body: | ||
|
||
``` | ||
Зарегистрировано событие на элементе BODY | ||
``` | ||
|
||
❓ Зачем это нужно | ||
|
||
- Удобно использовать для делегирования событий: можно вешать один обработчик на контейнер, а не на каждую кнопку; | ||
- Повышает производительность, т. к. можно использовать меньше обработчиков. | ||
|
||
☝️ Для остановки всплытия нужно использовать `event.stopPropagation()` в функции-обработчике события. | ||
|
||
```html | ||
<html> | ||
<body> | ||
<div id="container"> | ||
<button>Нажми на меня</button> | ||
</div> | ||
</body> | ||
</html> | ||
``` | ||
|
||
```js | ||
const button = document.querySelector('button') | ||
const container = document.getElementById('container') | ||
const body = document.querySelector('body') | ||
|
||
button.addEventListener('click', handleClick) | ||
container.addEventListener('click', handleClick) | ||
body.addEventListener('click', handleClick) | ||
|
||
function handleClick(event) { | ||
event.stopPropagation() | ||
console.log(`Зарегистрировано событие на элементе ${event.currentTarget.tagName}`) | ||
} | ||
``` | ||
Тогда при клике на нашу кнопку `handleClick()` будет вызвана только один раз. В консоли браузера мы увидим: | ||
``` | ||
Зарегистрировано событие на элементе BUTTON | ||
``` | ||
|
||
Это означает, что дальнейшее всплытие было остановлено вызовом `event.stopPropagation()`. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
name: 'Александр Кутепов' | ||
url: https://www.linkedin.com/in/kutepoff/ | ||
photo: photo.jpeg | ||
badges: | ||
- first-contribution-small | ||
--- | ||
|
||
Fullstack-разработчик, изучал React, влюбился во Vue. Отдыхаю после трудных задач, прибираясь в коде и занимаясь рефакторингом. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Тут не совсем верно. На кнопке нет слушателя и ничего не вызывается