Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Shadow DOM and events#549

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
dolgachio merged 2 commits intojavascript-tutorial:masterfromso-tati:master
Sep 29, 2023
Merged
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 52 additions & 52 deletions8-web-components/7-shadow-dom-events/article.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
#Shadow DOMand events
#Тіньовий DOMта події

The idea behind shadow tree is to encapsulate internal implementation details of a component.
Головна мета створення тіньового дерева -- це інкапсуляція внутрішньої реалізації компоненту.

Let's say, a click event happens inside a shadow DOMof `<user-card>` component. But scripts in the main document have no idea about the shadow DOM internals, especially if the component comes from a 3rd-party library.
Уявімо, користувач клікнув на якийсь елемент всередені тіньового DOMкомпоненту `<user-card>`, і відбулася подія click. Але ж скріпти в головному документі і гадки не мають про внутрішню будову тіньового DOM, особливо, якщо компонент походить зі сторонньої бібліотеки.

So, to keep the details encapsulated, the browser *retargets* the event.
Отже, для збереження інкапсуляції вмісту, браузер *змінює у цієї події цільовий(target) елемент*.

**Events that happen in shadow DOM have thehost element as thetarget, when caught outside of the component.**
**Події, що відбуваються у тіньовому DOM, мають його "host" у властивості `target` об'єкту події, якщо подія обробляється за межами компоненту.**

Here's a simple example:
Розглянемо простий приклад:

```html run autorun="no-epub" untrusted height=60
<user-card></user-card>
Expand All@@ -21,30 +21,30 @@ customElements.define('user-card', class extends HTMLElement {
<button>Click me</button>
</p>`;
this.shadowRoot.firstElementChild.onclick =
e => alert("Innertarget: " + e.target.tagName);
e => alert("target зсередини: " + e.target.tagName);
}
});

document.onclick =
e => alert("Outertarget: " + e.target.tagName);
e => alert("target ззовні: " + e.target.tagName);
</script>
```

If you click on the button, the messages are:
Клікнувши на кнопку, отримаємо наступні повідомлення:

1.Innertarget: `BUTTON` --internal event handler gets the correcttarget, the element inside shadow DOM.
2.Outertarget: `USER-CARD` --document event handler gets shadow host as the target.
1. target зсередини: `BUTTON` --внутрішній обробник подій отримує правильнийtarget -- елемент всередині тіньового DOM.
2. target ззовні: `USER-CARD` --обробник подій документу отримує тіньовий хост в якості target події.

Event retargeting is a great thing to have, because the outer document doesn't have to know about component internals. From its point of view, the event happened on `<user-card>`.
Зміна target події -- чудова річ, бо зовнішній документ не повинен знати про внутрішній вміст компоненту. З цієї точки зору, подія відбулась в `<user-card>`.

**Retargeting does not occur if the event occurs on a slotted element, that physically lives in the light DOM.**
**Зміна target не відбувається, якщо подія починається з елементу зі слоту, що фактично знаходиться в звичайному світлому DOM.**

For example, if a user clicks on`<span slot="username">`in the example below, the event target is exactly this `span` element, for both shadow and light handlers:
Наприклад, якщо користувач клікає на`<span slot="username">`у прикладі, наведеному нижче, цільовим елементом є саме цей елемент `span`, для обох обробників -- звичайного (світлого) та тіньового:

```html run autorun="no-epub" untrusted height=60
<user-card id="userCard">
*!*
<span slot="username">John Smith</span>
<span slot="username">Іван Коваль</span>
*/!*
</user-card>

Expand All@@ -57,80 +57,80 @@ customElements.define('user-card', class extends HTMLElement {
</div>`;

this.shadowRoot.firstElementChild.onclick =
e => alert("Innertarget: " + e.target.tagName);
e => alert("target зсередини: " + e.target.tagName);
}
});

userCard.onclick = e => alert(`Outertarget: ${e.target.tagName}`);
userCard.onclick = e => alert(`target ззовні: ${e.target.tagName}`);
</script>
```

If a click happens on `"John Smith"`,for both inner and outer handlers thetargetis`<span slot="username">`.That's an element from the lightDOM,so no retargeting.
Якщо клік відбувся на `"Іван Коваль"`,для обох -- внутрішнього та зовнішнього -- обробників уtargetбуде елемент`<span slot="username">`.Це елемент зі світлогоDOM,тому зміна target не відбувається.

On the other hand, if the click occurs on an element originating from shadowDOM,e.g. on `<b>Name</b>`,then, as it bubbles out of the shadowDOM,its `event.target`is reset to `<user-card>`.
З іншого боку, якщо клік відбувся на елементі з тіньовогоDOM,напр. на `<b>Name</b>`,то коли він вспливає з тіньовогоDOM,його `event.target`стає `<user-card>`.

##Bubbling, event.composedPath()
##Спливання, event.composedPath()

For purposes of event bubbling, flattened DOM is used.
Для реалізації спливання подій (бульбашковий механізм) використовується підхід розгорнутого DOM.

So, if we have a slotted element, and an event occurs somewhere inside it, then it bubbles up to the`<slot>`and upwards.
Отже, якщо у нас є елемент у слоті, і подія відбувається десь всередині цього елементу, тоді вона підіймається до`<slot>`і вище.

The full path to the original event target, with all the shadow elements, can be obtained using `event.composedPath()`.As we can see from the name of the method, that path is taken after the composition.
Повний шлях до справжнього target елементу цієї події, включаючи всі тіньові елементи, можна отримати за допомогою `event.composedPath()`.Як видно з назви методу, він повертає шлях після складання всіх його елементів.

In the example above, the flattenedDOMis:
У наведеному вище прикладі зведенийDOMвиглядає так:

```html
<user-card id="userCard">
#shadow-root
<div>
<b>Name:</b>
<slot name="username">
<span slot="username">John Smith</span>
<span slot="username">Іван Коваль</span>
</slot>
</div>
</user-card>
```


So, for a click on`<span slot="username">`, a call to`event.composedPath()`returns an array: [`span`, `slot`, `div`, `shadow-root`, `user-card`, `body`, `html`, `document`, `window`]. That's exactly the parent chain from the targetelement in the flattenedDOM, after the composition.
Отже, для кліку по`<span slot="username">` виклик`event.composedPath()`повертає масив: [`span`, `slot`, `div`, `shadow-root`, `user-card`, `body`, `html`, `document`, `window`], що цілковито відображає батьківський ланцюжок, починаючи з targetелемента у зведеномуDOM після складання.

```warn header="Shadow tree details are only provided for`{mode:'open'}` trees"
If the shadow tree was created with`{mode: 'closed'}`,then thecomposed path starts from the host: `user-card`and upwards.
```warn header="Деталі тіньового дерева надаються лише для дерев з`{mode:'open'}`"
Якщо тіньове дерево було створено з`{mode: 'closed'}`,то тоді складений (composed) шлях починається від хоста: `user-card`і вище.

That's the similar principle as for other methods that work with shadowDOM.Internals of closed trees are completely hidden.
Це той самий принцип, що і для інших методів, які працюють із тіньовимDOM.Внутрішні частини закритих дерев повністю приховані.
```


## event.composed
##Властивістьevent.composed

Most events successfully bubble through a shadow DOM boundary. There are few events that do not.
Більшість подій успішно проходять через тіньову межу DOM. Є кілька подій, які нездатні на це.

This is governed by the `composed` event object property. If it's `true`,then the event does cross the boundary. Otherwise, it only can be caught from inside the shadow DOM.
Це регулюється властивістю об’єкта події `composed`. Якщо вона `true`,то подія дійсно може перетнути межу. В іншому випадку її можна буде перехопити лише зсередини тіньового DOM.

If you take a look at[UI Events specification](https://www.w3.org/TR/uievents),most events have `composed: true`:
Якщо ви подивитесь на[UI Events specification](https://www.w3.org/TR/uievents),більшість подій мають `composed: true`:

- `blur`, `focus`, `focusin`, `focusout`,
- `click`, `dblclick`,
- `mousedown`, `mouseup` `mousemove`, `mouseout`, `mouseover`,
- `wheel`,
- `beforeinput`, `input`, `keydown`, `keyup`.

All touch events and pointer events also have `composed: true`.
Усі сенсорні події та події курсору також мають `composed: true`.

There are some events that have `composed: false` though:
Та існують деякі події, що мають `composed: false`:

- `mouseenter`, `mouseleave` (they do not bubble at all),
- `mouseenter`, `mouseleave` (ці події взагалі не вспливають),
- `load`, `unload`, `abort`, `error`,
- `select`,
- `slotchange`.

These events can be caught only on elements within the sameDOM,where the eventtargetresides.
Ці події можна перехопити лише на елементах у межах того ж самогоDOM,де знаходитьсяtargetелемент події.

## Custom events
##Генерація подій (Custom events)

When we dispatch custom events, we need to set both `bubbles`and `composed`properties to`true` for it to bubble up and out of the component.
Коли ми генеруємо користувацькі події, нам потрібно встановити для властивостей `bubbles`і `composed`значення`true`, щоб вони вспливали та виходили за межі компонента.

For example, here we create `div#inner`in the shadowDOMof`div#outer`and trigger two events on it. Only the one with `composed: true` makes it outside to the document:
Наприклад, тут ми створюємо `div#inner`у тіньовомуDOM `div#outer`і запускаємо дві події для нього. Лише та, що має `composed: true`, виходить за межі документа:

```html run untrusted height=0
<div id="outer"></div>
Expand DownExpand Up@@ -167,26 +167,26 @@ inner.dispatchEvent(new CustomEvent('test', {
</script>
```

##Summary
##Підсумки

Events only cross shadow DOM boundaries if their`composed`flag is set to `true`.
Лише ті події перетинають тіньові межі DOM, у прапорці`composed`яких задано значення `true`.

Built-in events mostly have `composed: true`,as described in the relevant specifications:
Вбудовані події здебільшого мають `composed: true`,як описано у відповідних специфікаціях:

- UI Events <https://www.w3.org/TR/uievents>.
- Touch Events <https://w3c.github.io/touch-events>.
- Pointer Events <https://www.w3.org/TR/pointerevents>.
- ...And so on.
-Події інтерфейсу користувача (UI Events) <https://www.w3.org/TR/uievents>.
-Сенсорні події (Touch Events) <https://w3c.github.io/touch-events>.
-Події вказівника (Pointer Events) <https://www.w3.org/TR/pointerevents>.
- ...тощо.

Some built-in events that have `composed: false`:
Деякі вбудовані події, що мають `composed: false`:

- `mouseenter`, `mouseleave` (also do not bubble),
- `mouseenter`, `mouseleave` (зовсім не спливають),
- `load`, `unload`, `abort`, `error`,
- `select`,
- `slotchange`.

These events can be caught only on elements within the same DOM.
Ці події можуть бути перехоплені тільки на елементах у межах того самого DOM.

If we dispatch a`CustomEvent`,then we should explicitly set `composed: true`.
Якщо ми генеруємо`CustomEvent`,тоді нам слід явно встановити `composed: true`.

Please note that in case of nested components, one shadowDOMmay be nested into another. In that case composed events bubble through all shadow DOM boundaries. So, if an event is intended only for the immediate enclosing component, we can also dispatch it on the shadow host and set`composed: false`.Then it's out of the component shadow DOM, but won't bubble up to higher-level DOM.
Зверніть увагу, що у випадку вкладених компонентів один тіньовийDOMможе бути вкладений в інший. У цьому випадку складені події проходять через усі тіньові межі DOM. Отже, якщо подія призначена лише для безпосередньо найближчого зовнішнього батьківського компонента, ми також можемо ініціювати її на тіньовому хості і встановити`composed: false`.В такому разі подія виходить із тіньової DOM компонента, але не переходить до DOM вищого рівня.

[8]ページ先頭

©2009-2025 Movatter.jp