You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 8-web-components/7-shadow-dom-events/article.md
+23-23Lines changed: 23 additions & 23 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,12 +1,12 @@
1
1
# Теневой DOM и события
2
2
3
-
Идея, стоящая за теневым DOM-деревом -- это инкапсуляция реализации внутренних деталей компонента.
3
+
Смысл создания теневого DOM-дерева - это инкапсуляция внутренних деталей компонента.
4
4
5
-
Допустим, клик произошёл внутри теневого DOM на компоненте `<user-card>`. Но скрипты основного документа ничего не знают о внутреннем устройстве теневой DOM-структуры, в особенности, если компонент из кода сторонней библиотеки или вроде того.
5
+
Допустим, клик произошёл внутри теневого DOM на компоненте `<user-card>`. Но скрипты основного документа ничего не знают о внутреннем устройстве теневой DOM-структуры, в особенности, если компонент создан сторонней библиотекой.
6
6
7
-
Таким образом, чтобы не усложнять, браузер *меняет у этого события целевой элемент*.
7
+
Поэтому, чтобы не нарушать инкапсуляцию, браузер *меняет у этого события целевой элемент*.
8
8
9
-
**События, которые пойманы в теневом DOM, но вне компонента, имеют в качестве целевого элемента -- элемент-хозяин.**
9
+
**События, которые произошли в теневом DOM, но пойманы снаружи этого DOM, имеют элемент-хозяин в качестве целевого элемента `event.target`.**
10
10
11
11
Рассмотрим простой пример:
12
12
@@ -37,9 +37,9 @@ document.onclick =
37
37
38
38
Хорошо, что браузер подменяет целевые элементы событий. Потому что внешний документ ничего не знает о внутреннем устройстве компонента. С его (внешнего документа) точки зрения, событие происходит на `<user-card>`.
39
39
40
-
**Подмена целевого элемента не происходит, если событие берёт начало на "слотовом" элементе, который фактически находится в обычном, "светлом" DOM.**
40
+
**Подмена целевого элемента не происходит, если событие берёт начало на элементе из слота, который фактически находится в обычном, светлом DOM.**
41
41
42
-
Например, если пользователь кликнет на `<span slot="username">`из кода ниже -- целевой элемент события будет именно этим элементом для обоих обработчиков -- теневого и обычного ("светлого"):
42
+
Например, если пользователь кликнет на `<span slot="username">`в примере ниже -- целевой элемент события будет именно этот `span` для обоих обработчиков -- теневого и обычного (светлого):
Если клик произойдёт на `"John Smith"`, то для обоих обработчиков -- внутреннего и внешнего -- целевым элементом будет `<span slot="username">`. Это элемент обычного ("светлого") DOM, так что подмены не происходит.
68
+
Если клик произойдёт на `"John Smith"`, то для обоих обработчиков -- внутреннего и внешнего -- целевым элементом будет `<span slot="username">`. Это элемент обычного (светлого) DOM, так что подмены не происходит.
69
69
70
-
С другой стороны, если клик произойдёт на элементе, происходящем из теневого DOM, например, на `<b>Имя</b>`, то как только всплытие выйдет за пределы теневой DOM-структуры, его `event.target` станет `<user-card>`.
70
+
С другой стороны, если клик произойдёт на элементе, который находится в теневом DOM, например, на `<b>Имя</b>`, то как только всплытие выйдет за пределы теневой DOM-структуры, его `event.target` станет `<user-card>`.
71
71
72
72
## Всплытие и метод event.composedPath()
73
73
74
-
Для обеспечения всплытия событий используются развёрнутые DOM-структуры (Flattened DOM).
74
+
Для обеспечения всплытия событий используется развёрнутый DOM.
75
75
76
-
Таким образом, если мы имеем "слотовый" (slotted) элемент и событие происходит где-то внутри него, то оно всплывает до `<slot>` и выше.
76
+
Таким образом, если у нас есть элемент в слоте, и событие происходит где-то внутри него, то оно всплывает до `<slot>` и выше.
77
77
78
-
Полный путь изначального целевого элемента, со всеми корневыми элементами теневого DOM-дерева, можно получить, воспользовавшись методом `event.composedPath()`. Как видно из названия -- это метод, возвращающий путь, полученный после задания композиции.
78
+
Полный путь к изначальному целевому элементу, со всеми теневыми элементами, можно получить, воспользовавшись методом `event.composedPath()`. Как видно из названия, этот метод возвращает путьпосле композиции.
79
79
80
80
В примере выше развёрнутое DOM-дерево будет таким:
Так что, при клике по `<span slot="username">` вызов метода `event.composedPath()` вернёт массив: [`span`, `slot`, `div`, `shadow-root`, `user-card`, `body`, `html`, `document`, `window`]. Что в точности отражает цепочку родителей от целевого элемента в развёрнутой DOM-структуре после задания композиции.
95
+
Так что, при клике по `<span slot="username">` вызов метода `event.composedPath()` вернёт массив: [`span`, `slot`, `div`, `shadow-root`, `user-card`, `body`, `html`, `document`, `window`]. Что в точности отражает цепочку родителей от целевого элемента в развёрнутой DOM-структуре после композиции.
96
96
97
97
```warn header="Детали теневого DOM-дерева доступны только для деревьев с `{mode:'open'}`"
98
-
Если теневое DOM-дерево было создано с `{mode: 'closed'}`, то после задания композиции путь будет начинаться с элемента-хозяина: `user-card` и дальше вверх по дереву.
98
+
Если теневое DOM-дерево было создано с `{mode: 'closed'}`, то после композиции путь будет начинаться с элемента-хозяина: `user-card` и дальше вверх по дереву.
99
99
100
-
Этот метод работает по тем же принципам, что и остальные методы теневого DOM. Внутреннее устройство свёрнутых DOM-деревьев совершенно скрыто.
100
+
Этот метод следует тем же принципам, что и остальные. Внутреннее устройство закрытых DOM-деревьев совершенно скрыто.
101
101
```
102
102
103
103
104
104
## Свойство: event.composed
105
105
106
-
Большинство событий успешно всплывают, выходя за границы теневого DOM. Но есть некоторые события, которые ведут себя иначе.
106
+
Большинство событий успешно всплывают сквозь границу теневого DOM. Но не все.
107
107
108
108
Это поведение регулируется с помощью свойства `composed` объекта события. Если оно `true`, то событие пересекает границу. Иначе, оно может быть поймано лишь внутри теневого DOM.
Когда мы инициируем сгенерированное событие, чтобы оно всплывало за пределы компонента, нужно установить оба свойства: `bubbles` и `composed` -- со значением `true`.
131
+
Когда мы генерируем своё событие, то, чтобы оно всплывало за пределы компонента, нужно установить оба свойства: `bubbles` и `composed` - в значение `true`.
132
132
133
-
Например, здесь мы создаём элемент `div#inner` в теневом DOM-дереве элемента `div#outer` и генерируем на нём два события. Только одно с флагом `composed: true` выйдет за пределы документа:
133
+
Например, здесь мы создаём элемент `div#inner` в теневом DOM-дереве элемента `div#outer` и генерируем на нём два события. Только одно с флагом `composed: true` выйдет наружу, в документ:
У некоторых встроенных событий всё же стоит `composed: false`:
182
182
183
-
-`mouseenter`, `mouseleave` (также не всплывают),
183
+
-`mouseenter`, `mouseleave` (вообще не всплывают),
184
184
-`load`, `unload`, `abort`, `error`,
185
185
-`select`,
186
186
-`slotchange`.
187
187
188
188
Эти события могут быть пойманы только на элементах, принадлежащих тому же DOM-дереву.
189
189
190
-
Если мы инициируем`CustomEvent`, то должны явно поставить флаг `composed: true`.
190
+
Если мы генерируем своё событие`CustomEvent`, то должны явно поставить флаг `composed: true`.
191
191
192
-
Обратите внимание, что в случае вложенных компонентов, события с заданной композицией всплывают через границы всего теневого DOM. Поэтому, если событие предназначено только для непосредственного ближайшего компонента, то мы также должны инициировать это событие на элементе-хозяине. Иначе оно выйдет за пределы своего теневого DOM.
192
+
Обратите внимание, что в случае вложенных компонентов теневые DOM могут быть вложены друг в друга. События с флагом `composed` всплывают через границы всех теневых DOM. Поэтому, если событие предназначено только для ближайшего внешнего компонента-родителя, мы можем инициировать его на элементе-хозяине. Тогда оно будет уже вне теневого DOM компонента, но не выплывает наружу в "ещё более внешний" DOM.
0 commit comments