Skip to content

fix(2-1.3): Review DOM navigation acticle #518

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

Merged
Merged
Changes from all 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
46 changes: 23 additions & 23 deletions 2-ui/1-document/03-dom-navigation/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ libs:

# Навігація по DOM

DOM дозволяє нам робити будь-що з елементами та їх вмістом, але спочатку нам потрібно знайти відповідний DOM об’єкт.
DOM дозволяє нам робити будь-що з елементами та їх вмістом, але спочатку нам потрібно отримати відповідний DOM об’єкт.

Усі операції з DOM починаються з об’єкта `document`. Це головна "точка входу" в DOM. З нього ми можемо отримати доступ до будь-якого вузла.

Ось зображення структури посилань, які дозволяють переміщатися між вузлами DOM:
Ось так виглядають основні посилання, які дозволяють переміщатися між вузлами DOM:

![](dom-links.svg)

Expand All @@ -22,10 +22,10 @@ DOM дозволяє нам робити будь-що з елементами
Найвищі вузли дерева доступні безпосередньо як властивості `document`:

`<html>` = `document.documentElement`
: Найвищий вузол документа -- `document.documentElement`. Це вузол DOM тегу `<html>`.
: Найвищий вузол документа -- `document.documentElement`. В DOM він відповідає тегу `<html>`.

`<body>` = `document.body`
: Для доступу до DOM вузлу `<body>` часто використовують елемент -- `document.body`.
: Іншим широко використовуваним вузлом DOM є елемент `<body>` -- `document.body`.

`<head>` = `document.head`
: Тег `<head>` доступний як `document.head`.
Expand Down Expand Up @@ -63,7 +63,7 @@ DOM дозволяє нам робити будь-що з елементами
У DOM значення `null` означає "не існує" або "такого вузла немає".
```

## Дочірні елементи: childNodes, firstChild, lastChild
## Дочірні вузли: childNodes, firstChild, lastChild

Відтепер ми будемо використовувати два терміни:

Expand All @@ -86,7 +86,7 @@ DOM дозволяє нам робити будь-що з елементами
</html>
```

...А нащадками `<body>` є не тільки прямі дочірні елементи `<div>`, `<ul>`, але й більш глибоко вкладені елементи, такі як `<li>` (дочірній елемент `<ul>`) та `<b>` (дочірній елемент `<li>`) -- тобто усе піддерево.
...А нащадками `<body>` є не тільки прямі дочірні елементи `<div>`, `<ul>`, але й більш глибоко вкладені елементи, такі як `<li>` (дочірній елемент `<ul>`) та `<b>` (дочірній елемент `<li>`) -- тобто усі елементи піддерева.

**Колекція `childNodes` містить список усіх дочірніх вузлів, включаючи текстові вузли.**

Expand Down Expand Up @@ -115,9 +115,9 @@ DOM дозволяє нам робити будь-що з елементами
</html>
```

Зверніть увагу на цікаву деталь. Якщо ми запустимо наведений вище приклад, останнім показаним елементом буде `<script>`. Насправді нижче в документі є більше речей, але на момент виконання сценарію браузер його ще не прочитав, тому скрипт його не бачить.
Зверніть увагу на цікаву деталь. Якщо ми запустимо наведений вище приклад, останнім показаним елементом буде `<script>`. Насправді нижче в документі є більше коду, але на момент виконання скрипту браузер його ще не прочитав, тому скрипт його не бачить.

**Властивості `firstChild` і `lastChild` надають швидкий доступ до першого та останнього дочірнього елемента.**
**Властивості `firstChild` і `lastChild` надають швидкий доступ до першого та останнього дочірнього вузла.**

Це лише скорочення. Якщо існують дочірні вузли, то завжди вірно наступне:
```js
Expand All @@ -129,19 +129,19 @@ elem.childNodes[elem.childNodes.length - 1] === elem.lastChild

### DOM колекції

Як бачимо, `childNodes` виглядає як масив. Але насправді це не масив, а скоріше *колекція* -- спеціальний ітеративний об’єкт, подібний до масиву.
Як бачимо, `childNodes` виглядає як масив. Але насправді це не масив, а скоріше *колекція* -- спеціальний ітеративний об’єкт-псевдомасив.

Є два важливих наслідки:
Є два важливих наслідки з цього:

1. Ми можемо використовувати `for..of`, щоб перебирати його:
```js
for (let node of document.body.childNodes) {
alert(node); // показує всі вузли з колекції
}
```
Це тому, що він ітерований (підчас перебору може надавати властивість `Symbol.iterator`).
Це працює, бо колекція є ітерованим об’єктом (є потрібний для цього метод `Symbol.iterator`).

2. Методи масиву не працюватимуть, тому що це не масив:
2. Методи масиву не працюватимуть, бо колекція це не масив:
```js run
alert(document.body.childNodes.filter); // undefined (методу filter немає!)
```
Expand Down Expand Up @@ -180,9 +180,9 @@ elem.childNodes[elem.childNodes.length - 1] === elem.lastChild
</body>
````

## Сусідні і батьківський елементи
## Сусіди та батьківський вузол

*Сусіди*, або сусідні вузли -- це вузли, які мають однаковий батьківський елемент.
*Сусіди*, або сусідні вузли -- це вузли, які є нащадками одного батька.

Наприклад, тут `<head>` і `<body>` є сусідами:

Expand Down Expand Up @@ -214,25 +214,25 @@ alert( document.body.previousSibling ); // HTMLHeadElement

## Навігація лише за елементами

Властивості навігації, перераховані вище, відносяться до *всіх* вузлів. Наприклад, у `childNodes` ми можемо побачити як текстові вузли, так і вузли елементів і навіть вузли коментарів, якщо вони існують.
Властивості навігації, перераховані вище, відносяться до *всіх* вузлів в документі. Наприклад, у `childNodes` ми можемо побачити як текстові вузли, так і вузли елементів і навіть вузли коментарів, якщо вони існують.

Але для багатьох задач нам не потрібні текстові вузли чи вузли коментарів. Ми хочемо маніпулювати вузлами елементів, які представляють теги та формують структуру сторінки.

Тож давайте подивимося властивости зі спеціальними посиланнями, які враховують лише *вузли-елементи*:
Тож давайте розглянемо додатковий набір посилань, які враховують лише *вузли-елементи*:

![](dom-links-elements.svg)

Посилання подібні до наведених вище, лише із словом `Element` всередині:

- `children` -- тільки ті дочірні елементи, які є вузлами-елементами.
- `children` -- колекція дітей, які є елементами.
- `firstElementChild`, `lastElementChild` -- перший і останній дочірні елементи.
- `previousElementSibling`, `nextElementSibling` -- сусідні елементи.
- `parentElement` -- батьківський елемент.

````smart header="Чому `parentElement`? Чи може батько бути *не елементом?*"
Властивість `parentElement` повертає батьківський елемент "element", тоді як `parentNode` повертає батьківський "будь-який вузол". Ці властивості зазвичай однакові: обидва вони отримують батьківський елемент.
Властивість `parentElement` повертає батьківський елемент "element", тоді як `parentNode` повертає батьківський "будь-який вузол". Ці властивості зазвичай однакові: обидві вони отримують батьківський елемент.

За одним винятком `document.documentElement`:
За винятком `document.documentElement`:

```js run
alert( document.documentElement.parentNode ); // document
Expand Down Expand Up @@ -283,12 +283,12 @@ while(elem = elem.parentElement) { // ідемо вгору, поки не ді
Таблиці є чудовим прикладом цього і представляють особливо важливий випадок:

**Елемент`<table>`** підтримує (на додаток до наведених вище) такі властивості:
- `table.rows` -- набір елементів `<tr>` таблиці.
- `table.rows` -- колекція рядків `<tr>` таблиці.
- `table.caption/tHead/tFoot` -- посилання на елементи `<caption>`, `<thead>`, `<tfoot>`.
- `table.tBodies` -- колекція елементів `<tbody>` (за стандартом може бути багато, але завжди буде принаймні один -- навіть якщо його немає у вихідному HTML, браузер помістить його в DOM).

**Елементи `<thead>`, `<tfoot>`, `<tbody>`** забезпечують властивість `rows`:
- `tbody.rows` -- колекція `<tr>` всередині.
- `tbody.rows` -- колекція рядків `<tr>` всередині.

**`<tr>`:**
- `tr.cells` -- колекція клітинок `<td>` і `<th>` всередині заданого рядка `<tr>`.
Expand All @@ -311,9 +311,9 @@ while(elem = elem.parentElement) { // ідемо вгору, поки не ді
</table>

<script>
// get td with "two" (first row, second column)
// отримати td з "two" (перший рядок, друга колонка)
let td = table.*!*rows[0].cells[1]*/!*;
td.style.backgroundColor = "red"; // highlight it
td.style.backgroundColor = "red"; // виділити червоним
</script>
```

Expand Down