Запитаний елемент не підключено до моделі dom. Ще один блог веб-розробника. Вибір елементів за класом CSS

У цьому уроці ми розберемо основи роботи з подіями, атрибутами та getElementById мовою JavaScript.

У попередніх уроках ми з вами вивчали базові можливості JavaScript. Починаючи з цього уроку ми займемося тим, для чого власне JavaScript і призначений - ми змінюватимемо елементи HTML сторінки та реагуватимемо на дії користувача. Наші скрипти стануть більш видовищними та корисними.

Почнемо ми з того, що навчимо наш код реагувати на дії користувача сайту. Наприклад, користувач натисне кудись мишкою, а наш код у відповідь повинен буде обробити це натискання і вивести на екран будь-яку інформацію.

Дії користувача, які ми можемо відстежити через JavaScript, називаються подіями. Події можуть бути такими: клікмишкою на елемент сторінки, наведеннямишкою на елемент сторінки чи навпаки - доглядкурсор миші з елементом і так далі. Крім того, є події, що не залежать від дій користувача, наприклад подія із завантаження HTML сторінки в браузер.

У JavaScript існує кілька способів роботи з подіями. Ми почнемо з найпростішого з них.

Основи роботи з подіями

Найпростіший спосіб встановити реакцію елемента на певну подію - вказати її за допомогою атрибута для певного тега. Наприклад, події "натискання мишкою"відповідає атрибут onclick "наведення мишкою"- атрибут onmouseover , а події "догляд курсору з елемента"- атрибут наобсязі.

Значенням атрибуту з подією служить JavaScript код. У наступному прикладі по натисканню мишкою на кнопкувиконається функція alert:

А зараз на клікуна елемент виконається функція func :

function func() ( alert("!"); )

Можна виконати не одну функцію, а кілька:

function func1() ( alert("1"); ) function func2() ( alert("2"); )

Якщо всередині атрибуту вам потрібні подвійні лапки (наприклад, для рядка) і зовнішні лапки атрибута теж подвійні - onclick="alert("!")"- такий код не працюватиме.

З цим можна боротися кількома способами: можна змінити зовнішні лапки на одинарні onclick="alert("!")", можна також заекранувати внутрішні лапки зворотним слішем onclick="alert(\"!")"або просто перенести JavaScript код з атрибуту в функцію, а в атрибуті залишити тільки ім'я функції onclick="func()".

Те саме буде, якщо ви зовнішні лапки атрибута ставите одинарними і для рядка теж використовуєте одинарні: onclick="alert("!")"- Тут також все вирішується аналогічними методами.

Таблиця атрибутів для подій Робота з getElementById

Зараз ми з вами навчимося отримувати елементи HTML сторінки і проводити з ними різні маніпуляції (ми зможемо змінювати, наприклад, їх текст та колір та багато інших корисних речей).

Нехай у нас на сторінці є тег із атрибутом id у значенні test. Запишемо посилання на цей тег у змінну elem. Для цього ми повинні скористатися методом getElementById, який отримує елемент за його ID.

Цей запис відбудеться по кліку на кнопку, якою ми задали атрибут onclick . Після натискання цієї кнопки спрацює функція func , яка знайде на HTML сторінці елемент з id рівним test і запише посилання на ньогов змінну elem:

Тепер у змінній elem у нас лежить посилання на елемент з атрибутом id у значенні test. Сама змінна elem є об'єктом.

Цей об'єкт і тег HTML сторінки пов'язані один з одним - ми можемо змінити будь-які властивості об'єкта elem і при цьому побачимо зміни на сторінці HTML, які відбудуться з отриманим нами елементом.

Погляньмо, як це відбувається на практиці.

Основи роботи з атрибутами HTML через JavaScript

Зараз ми будемо зчитувати та змінювати атрибути тегів. Нехай у нас знову дано інпут з id рівним test і кнопка , на кліку на яку запускатиметься функція func :

Всередині функції func ми матимемо наш інпут на його idі запишемо посилання на нього в змінну elem:

function func() ( var elem = document.getElementById("test"); )

Давайте тепер виведемо на екран вміст атрибутів нашого інпуту. Щоб отримати доступ, наприклад, до атрибуту value, слід написати наступне: elem.value , де elem - це змінна, у якому ми з допомогою getElementById записали посилання наш елемент, а value - це атрибут тега, який нас цікавить.

Ми можемо вивести вміст атрибуту через alert таким чином – alert(elem.value) – або записати в якусь змінну. Давайте зробимо це:

function func() ( var elem = document.getElementById("test"); alert(elem.value); //виведе "!" )

Ми можемо так само зчитувати значення та інших атрибутів, наприклад так - elem.id - ми вважаємо значення атрибута id, а так - elem.type - значення атрибута type. Дивіться приклад:

function func() ( var elem = document.getElementById("test"); alert(elem.value); //виведе "!" alert(elem.id); //виведе "test" alert(elem.type); //виведе "text")

Можна не лише зчитувати значення атрибутів, а й змінювати їх. Щоб, наприклад, змінити значення атрибута value , потрібно легко привласнити його конструкції elem.value :

function func() ( var elem = document.getElementById("test"); elem.value = "www"; //присвоим новое значение атрибуту value } !}

HTML код виглядатиме так (значення атрибуту value стане www):

Ну, а тепер найскладніше - можна не вводити змінну elem, а будувати ланцюжок з крапок таким чином:

function func() ( alert(document.getElementById("test").value); //виведе "!" )

Таким же чином (ланцюжком) можна робити і перезапис атрибутів:

function func() ( document.getElementById("test").value = "www"; }!}

Однак, в більшості випадків введення змінної зручніше. Порівняйте два приклади - зараз я ввів змінну elem і можу зчитувати будь-яку кількість атрибутів, при цьому getElementById викликається тільки один раз:

function func() ( var elem = document.getElementById("test"); elem.value = "www"; elem.type = "submit"; }!}

А зараз я не вводжу нову змінну і тому мені доводиться викликати getElementById двічі:

function func() ( document.getElementById("test").value = "www"; document.getElementById("test").type = "submit"; }!}

На мій погляд, цей код став складнішим, хоча і займає на один рядок менше. Крім того, якщо я захочу змінити значення id з test на, наприклад www, мені доведеться робити це в багатьох місцях, що не дуже зручно.

на браузер. Пошук елементів на сторінці, який робить метод getElementById , є досить повільною операцією ( і взагалі будь-яка робота з елементами сторінки – це повільна операція- Запам'ятайте це).

У нашому випадку, якщо ми щоразу використовуємо getElementById , то браузер щоразу оброблятиме HTML сторінку і шукатиме елемент із заданим id кілька разів (не важливо, що id однакові - браузер проробить усі дії кілька разів), здійснюючи марні операції, які можуть уповільнити роботу браузера.

Якщо ми використовуємо змінну elem - ніякого пошуку по сторінці не відбувається (елемент вже знайдено і посилання на нього лежить в змінній elem ).

Винятки: атрибути class та for

Ви вже навчилися працювати з атрибутами через JavaScript і тепер настав час розповісти вам про те, що не все так просто – при роботі з атрибутами існує виняток – це атрибут class.

Це слово є спеціальним у JavaScript і тому ми не можемо просто написати elem.class, щоб рахувати значення атрибута class . Натомість слід писати elem.className.

У цьому прикладі на екран виводиться значення атрибута class :

function func() ( var elem = document.getElementById("test"); alert(elem.className); )

До речі, є інші атрибути, які називаються інакше, ніж властивість. Наприклад, атрибут for () відповідає властивість з назвою htmlFor .

Робота з this

Зараз ми з вами працюватимемо зі спеціальним об'єктом this , який вказує на поточний елемент (елемент у якому відбулася подія). Причому вказує так, ніби цей елемент отримано методом getElementById .

Давайте подивимося як працювати з цим і в чому зручність такого підходу.

Нехай ми маємо завдання натиснути на інпут вивести на екран вміст його value.

Поки що ви вмієте робити тільки таке рішення:

function func() ( var elem = document.getElementById("test"); alert(elem.value); )

В принципі, це рішення хороше, але представимо тепер, що у нас є багато інпутів і натискання на кожен нам потрібно виводити його value.

У цьому випадку в нас вийде щось таке:

function func1() ( var elem = document.getElementById("test1"); alert(elem.value); ) function func2() ( var elem = document.getElementById("test2"); alert(elem.value); ) function func3() ( var elem = document.getElementById("test3"); alert(elem.value); )

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

Якщо у нас буде 10 інпутів – то доведеться зробити 10 функцій, не зручно.

Спростимо наше завдання: передаватимемо параметром функції id поточного елемента. І замість великої кількості функцій все зведеться до однієї функції:

function func(id) ( var elem = document.getElementById(id); alert(elem.value); )

Однак таке рішення все одно має недолік - кожному елементу доведеться вводити різні id, що теж дещо незручно.

Отже, давайте нарешті розглянемо варіант розв'язання задачі через це.

Зробимо так, що кожен інпут виводитиме свій вміст за натисканням. Для цього параметром функції передамо об'єкт this , так: func(this) .

Наш цей передається параметром функції і потрапляє в змінну elem. Цей elem веде себе так, ніби отриманий таким чином: var elem = document.getElementById(...)Але отримувати його таким чином не треба, там уже все готове і можна користуватися. Наприклад, elem.value вказує на value нашого інпуту тощо.

Отже, ось найпростіше рішення нашого завдання:

function func(elem) ( alert(elem.value); )

Основи роботи з CSS

У JavaScript робота з властивостями CSS відбувається шляхом зміни значення атрибуту style для елемента. Наприклад, щоб змінити колір потрібно побудувати наступний ланцюжок - elem.style.color- і привласнити їй потрібне значення кольору:

function func() ( var elem = document.getElementById("test"); elem.style.color = "red"; )

Можна також і не вводити змінну elem, а побудувати дуже довгий ланцюжок.

Робота з DOM-моделлю

Кожен об'єкт Window має властивість document, що посилається на об'єкт Document. Цей об'єкт Document не є автономним об'єктом. Це центральний об'єкт великого API, відомого як об'єктна модель документа (DOM), який визначає порядок доступу до вмісту документа.

Огляд моделі DOM

Об'єктна модель документа (Document Object Model, DOM) – це фундаментальний прикладний програмний інтерфейс, що забезпечує можливість роботи з вмістом HTML та XML-документів. Прикладний програмний інтерфейс (API) моделі DOM не є особливо складним, але в ньому існує безліч архітектурних особливостей, які ви повинні знати.

Перш за все слід розуміти, що вкладені елементи HTML або XML-документів представлені у вигляді дерева об'єктів DOM. Деревоподібне подання HTML-документа містить вузли, що являють собою елементи або теги, такі як і

І вузли, що становлять рядки тексту. HTML-документ може містити вузли, що представляють HTML-коментарі. Розглянемо наступний простий HTML-документ:

Приклад документа Це HTML-документ

приклад простоготексту.

DOM-подання цього документа наводиться на наступній діаграмі:

Тим, хто ще не знайомий з деревоподібними структурами в комп'ютерному програмуванні, корисно дізнатися, що термінологія їхнього опису була запозичена у генеалогічних дерев. Вузол, розташований безпосередньо над цим вузлом, називається батьківськимстосовно даного вузла. Вузли, розташовані на один рівень нижче іншого вузла, є дочірнімистосовно даного вузла. Вузли, що знаходяться на тому ж рівні і мають того ж батька, називаються сестринськими. Вузли, розташовані на будь-яке число рівнів нижче за інший вузл, є його нащадками. Батьківські, прабатьківські та будь-які інші вузли, розташовані вище даного вузла, є його предками.

Кожен прямокутник на цій діаграмі є вузлом документа, представленого об'єктом Node . Зверніть увагу, що на малюнку зображено три різні типи вузлів. Коренем дерева є вузол Document, який представляє документ цілком. Вузли, що являють собою HTML-елементи, є вузлами типу Element, а вузли, що представляють текст, - вузлами типу Text. Document, Element та Text - це підкласи класу Node. Document та Element є двома найважливішими класами в моделі DOM.

Тип Node та його підтипи утворюють ієрархію типів, зображену на діаграмі нижче. Зверніть увагу на формальні відмінності між узагальненими типами Document та Element та типами HTMLDocument та HTMLElement. Тип Document представляє HTML і XML-документ, а клас Element є елементом цього документа. Підкласи HTMLDocument і HTMLElement представляють саме HTML-документ та її элементы:

На цій діаграмі слід також відзначити наявність великої кількості підтипів класу HTMLElement, що становлять конкретні типи HTML-елементів. Кожен із них визначає JavaScript-властивості, що відображають HTML-атрибути конкретного елемента або групи елементів. Деякі з цих специфічних класів визначають додаткові властивості чи методи, які є відображенням синтаксису мови розмітки HTML.

Вибір елементів документа

Робота більшості клієнтських програм мовою JavaScript однак пов'язані з маніпулюванням елементами документа. У ході виконання ці програми можуть використовувати глобальну змінну документ, що посилається на об'єкт Document. Однак, щоб виконати будь-які маніпуляції з елементами документа, програма повинна якимось чином отримати або вибрати об'єкти Element, що посилаються на ці елементи документа. Модель DOM визначає кілька способів вибірки елементів. Вибрати елемент або елементи документа можна:

    за значенням атрибуту id;

    за значенням атрибута name;

    на ім'я тега;

    на ім'я класу або класів CSS;

    збігу з певним селектором CSS.

Всі ці прийоми вибірки елементів описуються у наступних підрозділах.

Вибір елементів за атрибутом id

Усі HTML-елементи мають атрибути id. Значення цього атрибуту має бути унікальним у межах документа - жодні два елементи в тому самому документі не повинні мати однакові значення атрибута id. Вибрати елемент за унікальним значенням атрибута id можна за допомогою методу getElementById() об'єкта Document:

Var section1 = document.getElementById("section1");

Це найпростіший і найпоширеніший спосіб вибірки елементів. Якщо сценарію необхідно мати можливість маніпулювати якимось певним безліччю елементів документа, надайте значення атрибутам id цих елементів та використовуйте можливість їх пошуку за цими значеннями.

У версіях Internet Explorer нижче IE8 метод getElementById() шукає значень атрибутів id без урахування регістру символів і, крім того, повертає елементи, в яких буде знайдено збіг зі значенням атрибута name.

Вибір елементів за атрибутом name

HTML-атрибут name спочатку призначався для присвоєння імен елементам форм, і значення цього атрибута використовувалося, коли відправлялися дані форми на сервер. Подібно до атрибуту id, атрибут name присвоює ім'я елементу. Однак, на відміну від id, значення атрибута name не повинно бути унікальним: те саме ім'я можуть мати відразу кілька елементів, що цілком звичайно при використанні у формах радіокнопок і прапорців. Крім того, на відміну від id, атрибут name допускається вказувати лише в деяких HTML-елементах, включаючи форми, елементи форм та елементи .

Вибрати HTML-елементи, спираючись на значення їх атрибутів name, можна за допомогою методу getElementsByName() об'єкта Document:

Var radiobuttons = document.getElementsByName("favorite_color");

Метод getElementsByName() визначається не класом Document, а класом HTMLDocument, тому він доступний тільки в HTML-документах і не доступний у XML-документах. Він повертає об'єкт NodeList , який поводиться як доступний тільки для читання масив об'єктів Element.

У IE метод getElementsByName() повертає також елементи, значення атрибутів id яких збігаються із зазначеним значенням. Щоб забезпечити сумісність з різними версіями браузерів, необхідно уважно підходити до вибору значень атрибутів і не використовувати одні й ті ж рядки як значення атрибутів name та id.

Вибір елементів за типом

Метод getElementsByTagName() об'єкта Document дозволяє вибрати всі HTML або XML-елементи вказаного типу (або на ім'я тега). Наприклад, отримати подібний до масиву об'єкт, доступний тільки для читання, що містить об'єкти Element всіх елементів у документі, можна наступним чином:

Var spans = document.getElementsByTagName("span");

Подібно до методу getElementsByName(), getElementsByTagName() повертає об'єкт NodeList. Елементи документа входять у масив NodeList у тому порядку, як вони йдуть у документі, тобто. перший елемент

У документі можна вибрати так:

Var firstParagraph = document.getElementsByTagName("p");

Імена HTML-тегів не чутливі до регістру символів, і коли getElementsByTagName() застосовується до HTML-документу, він порівняє з ім'ям тега без урахування регістру символів. Змінна spans, створена вище, наприклад, буде включати також всі елементи, які записані як .

Можна отримати NodeList, що містить усі елементи документа, якщо передати методу getElementsByTagName() шаблонний символ *.

Крім того, клас Element також визначає метод getElementsByTagName(). Він діє так само, як і версія методу в класі Document, але вибирає тільки елементи, що є нащадками для елемента, щодо якого викликається метод. Тобто знайти всі елементи всередині першого елемента

Можна так:

Var firstParagraph = document.getElementsByTagName("p"); var firstParagraphSpans = firstParagraph.getElementsByTagName("span");

З історичних причин клас HTMLDocument визначає спеціальні властивості доступу до вузлів певних типів. Властивості images, formsі linksнаприклад, посилаються на об'єкти, які поводяться як масиви, доступні тільки для читання, що містять елементи , і (але ті теги які мають атрибут href). Ці властивості посилаються на об'єкти HTMLCollection, які багато в чому схожі на об'єкти NodeList, але можуть індексуватися значеннями атрибутів id і name.

Об'єкт HTMLDocument також визначає властивості-синоніми embeds і plugins , що є колекціями HTMLCollection елементів . Властивість anchors є нестандартною, але з її допомогою можна отримати доступ до елементів , що мають атрибут name, але не мають атрибут href. Властивість scripts визначено стандартом HTML5 і є колекцією HTMLCollection елементів.

Крім того, об'єкт HTMLDocument визначає дві властивості, кожна з яких посилається не на колекцію, а на єдиний елемент. Властивість document.body є елементом HTML-документа, а властивість document.head - елемент . Ці властивості завжди визначені в документі: навіть якщо у вихідному документі відсутні елементи і браузер створить їх неявно. Властивість documentElement об'єкта Document посилається на кореневий елемент документа. У HTML-документах він завжди представляє елемент .

Вибір елементів за класом CSS

Значенням HTML-атрибута class є список із нуля або більше ідентифікаторів, розділених пробілами. Він дає можливість визначати безліч пов'язаних елементів документа: будь-які елементи, що мають в атрибуті class один і той же ідентифікатор, є частиною однієї множини. Слово class зарезервовано у мові JavaScript, тому для зберігання значення HTML-атрибута class у клієнтському JavaScript використовується властивість className.

Зазвичай атрибут class використовується разом із каскадними таблицями стилів CSS, щоб застосувати загальний стиль відображення всім членам множини. Однак крім цього, стандарт HTML5 визначає метод getElementsByClassName() , що дозволяє вибирати безліч елементів документа на основі ідентифікаторів в їх атрибутах class.

Подібно до методу getElementsByTagName(), метод getElementsByClassName() може викликатися і для HTML-документів, і для HTML-елементів, і повертає «живий» об'єкт NodeList, що містить усі нащадки документа або елемента, що відповідають критерію пошуку.

Метод getElementsByClassName() приймає єдиний рядковий аргумент, але в рядку може бути вказано кілька ідентифікаторів, розділених пробілами. Відповідними будуть вважатися всі елементи, атрибути class яких містять усі вказані ідентифікатори. Порядок ідентифікаторів не має значення. Зверніть увагу, що і в атрибуті class, і в аргументі методу getElementsByClassName() ідентифікатори класів поділяються пробілами, а не комами.

Нижче наведено кілька прикладів використання методу getElementsByClassName():

// Знайти всі елементи з класом "warning" var warnings = document.getElementsByClassName("warning"); // Знайти всіх нащадків елемента з ідентифікаторами "log" // з класами "error" та "fatal" var log = document.getElementById("log"); var fatal = log.getElementsByClassName("fatal error");

Вибір елементів за допомогою селекторів CSS

Каскадні таблиці стилів CSS мають дуже потужні синтаксичні конструкції, відомі як селектори, що дозволяють описувати елементи чи безліч елементів документа. Поряд зі стандартизацією селекторів CSS3 інший стандарт консорціуму W3C, відомий як Selectors API , визначає методи JavaScript для отримання елементів, відповідних зазначеному селектору.

Ключовим у цьому API є метод querySelectorAll() об'єкта Document. Він приймає єдиний рядковий аргумент із селектором CSS і повертає об'єкт NodeList, що представляє всі елементи документа, що відповідають селектору.

На додаток до методу querySelectorAll() об'єкт документа також визначає метод querySelector() , подібний до методу querySelectorAll(), - з тією відмінністю, що він повертає тільки перший (у порядку проходження в документі) відповідний елемент або null, у разі відсутності відповідних елементів.

Ці два методи також визначаються класом Elements. Коли вони викликаються щодо елемента, пошук відповідності заданому селектору виконується у всьому документі, а потім результат фільтрується так, щоб залишилися тільки нащадки використаного елемента. Такий підхід може здатися таким, що суперечить здоровому глузду, оскільки він означає, що рядок селектора може включати предків елемента, для якого виконується зіставлення.

Структура документа та навігація за документом

Після вибору елемента документа іноді буває потрібно знайти структурно пов'язані частини документа (батько, брати, дочірній елемент). Об'єкт Document можна уявити як дерево об'єктів Node. Тип Node визначає властивості, що дозволяють переміщатися таким деревом. Існує ще один прикладний інтерфейс навігації за документом як дерева об'єктів Element.

Документи як дерева вузлів

Об'єкт Document, його об'єкти Element і об'єкти Text, які представляють текстові фрагменти у документі - вони є об'єктами Node. Клас Node визначає такі важливі властивості:

parentNode

Батьківський вузол даного вузла або null для вузлів, які не мають батька, таких як Document.

childNodes

Доступний для читання об'єкт, подібний до масиву (NodeList), що забезпечує подання дочірніх вузлів.

firstChild, lastChild

Перший та останній дочірні вузли або null, якщо цей вузол не має дочірніх вузлів.

nextSibling, previousSibling

Наступний та попередній братські вузли. Братськими називаються два вузли, що мають одного й того самого батька. Порядок їхнього прямування відповідає порядку прямування в документі. Ці властивості зв'язують вузли в список.

nodeType

Тип цього вузла. Вузли типу Document мають значення 9 у цій властивості. Вузли типу Element – ​​значення 1. Текстові вузли типу Text – значення 3. Вузли типу Comments – значення 8 та вузли типу DocumentFragment – ​​значення 11.

nodeValue

Текстовий вміст вузлів Text та Comment.

nodeName

Ім'я тега елемента Element, у якому всі символи перетворені на верхній регістр.

За допомогою цих властивостей класу Node можна послатися на другий дочірній вузол першого дочірнього вузла об'єкта Document, як показано нижче:

Document.childNodes.childNodes == document.firstChild.firstChild.nextSibling

Припустимо, що аналізований документ має такий вигляд:

TestHello World!

Тоді другим дочірнім вузлом першого дочірнього вузла буде елемент. У якості nodeType він містить значення 1 і у властивості nodeName - значення «BODY».

Однак, зверніть увагу, що цей прикладний інтерфейс є надзвичайно чутливим до змін у тексті документа. Наприклад, якщо додати документ до єдиного перекладу рядка між тегами і , цей символ перекладу рядка стане першим дочірнім вузлом (текстовим вузлом Text) першого дочірнього вузла, а другим дочірнім вузлом стане елемент , а не .

Документи як дерева елементів

Коли основний інтерес представляють самі елементи документа, а не текст в них (і символи пробілів між ними), набагато зручніше використовувати прикладний інтерфейс, що дозволяє інтерпретувати документ як дерево об'єктів Element, ігноруючи вузли Text і Comment, які також є частиною документа.

Першою частиною цього прикладного інтерфейсу є властивість children об'єктів Element. Подібно до властивості childNodes, його значенням є об'єкт NodeList. Однак, на відміну від властивості ChildNodes, список Children містить тільки об'єкти Element.

Зверніть увагу, що вузли Text та Comment не мають дочірніх вузлів. Це означає, що описана вище властивість Node.parentNode ніколи не повертає вузли типу Text або Comment. Значенням властивості parentNode будь-якого об'єкта Element завжди буде інший об'єкт Element або корінь дерева - об'єкт Document або DocumentFragment.

Другою частиною прикладного інтерфейсу навігації за елементами документа є властивості об'єкта Element, аналогічні властивостям доступу до дочірніх та братніх вузлів об'єкта Node:

першийЕlementChild, останнійElementChild

Схожі на властивості firstChild та lastChild, але повертають дочірні елементи.

NextElementSibling, попереднійElementSibling

Схожі на властивості nextSibling і previousSibling, але повертають братерські елементи.

childElementCount

Кількість дочірніх елементів. Повертає те саме значення, що й властивість children.length.

Ці властивості доступу до дочірніх та братських елементів стандартизовані та реалізовані у всіх поточних браузерах, крім IE.

На цьому уроці ми розглянемо, що таке DOM, навіщо він потрібний, а також те, як він будується.

Що таке DOM?

Браузер, коли запитує сторінку і отримує у відповіді сервера її вихідний HTML-код, повинен спочатку його розібрати. В процесі аналізу та аналізу HTML-коду браузер будує на основі нього DOM-дерево.

Після виконання цієї дії та ряду інших браузер приступає до відтворення сторінки. У цьому процесі він, звичайно, вже використовує створене ним DOM-дерево, а не вихідний HTML-код.

DOM – це об'єктна модель документа, яку браузер створює в пам'яті комп'ютера на підставі коду HTML, отриманого ним від сервера.

Якщо сказати по-простому, HTML-код - це текст сторінки, а DOM - це набір пов'язаних об'єктів, створених браузером при парсингу її тексту.

У Chrome вихідний код сторінки, який отримує браузер, можна переглянути у вкладці "Source" на панелі "Інструменти веб-розробника".


У Chrome інструменту, за допомогою якого можна було б подивитися створене ним DOM-дерево, немає. Але є представлення цього DOM-дерева у вигляді HTML-коду, воно є на вкладці «Elements». З таким поданням DOM веб-розробнику, звичайно, набагато зручніше працювати. Тому інструменту, який DOM представляв у вигляді деревоподібної структури немає.


Об'єкти в цій моделі утворюються практично з усього, що є в HTML (тегів, текстового контенту, коментарів і т.д.), включаючи сам документ. Зв'язки між цими об'єктами моделі формуються на підставі того, як HTML-елементи розташовані в коді відносно один одного .

При цьому DOM документа після його формування можна змінювати. При зміні DOM браузер практично миттєво перемальовує зображення сторінки. В результаті у нас малювання сторінки завжди відповідає DOM.

Для читання та зміни DOM програмний браузер надає нам DOM API або, іншими словами, програмний інтерфейс. DOM API - це набір величезної кількості різних об'єктів, їх властивостей і методів, які ми можемо використовувати для читання і зміни DOM .

p align="justify"> Для роботи з DOM в більшості випадків використовується JavaScript, т.к. на сьогоднішній день це єдина мова програмування, скрипти якою можуть виконуватися в браузері.

Навіщо нам потрібний DOM API? Він нам потрібний для того, щоб ми могли за допомогою JavaScript змінювати сторінку на літу, тобто. робити її динамічною та інтерактивною.

DOM API надає нам (розробникам) безліч методів, за допомогою яких ми можемо змінювати все що є на сторінці, а також взаємодіяти з користувачем. Тобто. Цей програмний інтерфейс дозволяє нам створювати складні інтерфейси, форми, виконувати обробку дій користувачів, додавати та видаляти різні елементи на сторінці, змінювати їх вміст, властивості (атрибути) та багато іншого.

Зараз у вебі практично немає сайтів у сценаріях яких була б відсутня робота з DOM.

Із чого складається HTML-код сторінки?

Перед тим, як перейти до вивчення об'єктної моделі документа необхідно спочатку згадати, що являє собою вихідний код веб-сторінки (HTML-документа).

Вихідний код веб-сторінки складається з тегів, атрибутів, коментарів та тексту. Теги – це базова синтаксична конструкція HTML. Більшість із них є парними. У цьому випадку один з них відкриває, а інший - закриває. Одна така пара тегів утворює HTML-елемент. HTML-елементи можуть мати додаткові параметри – атрибути.

У документі для створення певної розмітки одні елементи знаходяться всередині інших. В результаті HTML-документ можна подати як безліч вкладених один в одного HTML-елементів.

Як приклад розглянемо наступний HTML код:

Заголовок сторінки Назва статті Розділ статті

Вміст статті

У цьому коді кореневим елементом є html. У нього вкладені елементи head та body. Елемент head містить title, а body – h1 та div. Елемент div у свою чергу містить h2 і p.

Тепер розглянемо, як браузер на основі HTML коду будує DOM-дерево.

Як будується DOM-дерево документа?

Як вже було описано вище, браузер будує дерево на основі HTML-елементів та інших сутностей вихідного коду сторінки. За виконання цього процесу він враховує вкладеність елементів друг в друга.

В результаті браузер отримане DOM-дерево використовує не тільки у своїй роботі, але й надає нам API для зручної роботи з ним через JavaScript.

Під час будівництва DOM браузер створює з HTML-елементів, тексту, коментарів та інших сутностей цієї мови об'єкти (вузли DOM-дерева).

У більшості випадків веб-розробників цікавлять лише об'єкти (вузли), утворені з HTML-елементів.

При цьому браузер не просто створює об'єкти з HTML-елементів, а також пов'язує їх між собою певними зв'язками залежно від того, як кожен з них відноситься до іншого коду.

Елементи, які знаходяться безпосередньо в деякому елементі, по відношенню до нього дітьми. А він для кожного є батьком. Крім цього, всі ці елементи стосовно один одного є сиблінгами (братами).

При цьому HTML будь-який елемент завжди має одного з батьків (HTML-елемент, в якому він безпосередньо розташований). У HTML елемент не може мати кілька батьків. Виняток становить лише елемент html. В нього немає батька.

Щоб отримати DOM-дерево, оскільки його будує браузер, необхідно просто «вибудувати» всі елементи залежно від їхнього ставлення один до одного.

Створення DOM-дерева виконується зверху донизу.

У цьому коренем DOM-дерева завжди є сам документ (вузол document). Далі дерево будується залежно від структури HTML-коду.

Наприклад, HTML-код, який ми розглядали вище, матиме наступне DOM-дерево:


У самому верху цього дерева знаходиться вузол document. Цей вузол пов'язаний з html, він є його дитиною. Вузол HTML утворений елементом HTML (...). Вузли head (...) та body (...) мають батьківський зв'язок з html. Стосовно один одному вони є сиблінгами, т.к. мають одного з батьків. Вузол head пов'язаний з title (lt;title>...), він його дитиною. Вузли h1 і div пов'язані з body , він є батьком. Вузол div пов'язаний з h2(...) і p(), вони є його дітьми.

Починається дерево як було зазначено вище з об'єкта (вузла) document . Він, у свою чергу, має один дочірній вузол, утворений елементом html (...). Елементи head (...) та body (...) знаходяться в html і, отже, є його дітьми. Далі вузол head є батьківським для title(lt;title>...). Елементи h1 і div вкладені в body, отже є його дітьми. У div безпосередньо розташовані елементи h2(...) та p(). Це означає, що вузол div для кожного є батьківським.

Ось так просто будується DOM-дерево в браузері на основі HTML-коду.

Навіщо знати, як будується DOM дерево? По-перше, це розуміння того середовища, в якому ви хочете щось змінювати. По-друге, більшість дій під час роботи з DOM зводиться до пошуку (вибору) необхідних елементів. Не знаючи як влаштовано DOM-дерево і зв'язки між вузлами знайти певний елемент у ньому буде досить важко.

Завдання

На основі DOM-дерева, представленого на малюнку, створіть HTML-код.



Об'єктна модель документа, або DOM, є програмним інтерфейсом доступу до елементів веб-сторінок. По суті, це API сторінки, що дозволяє читати та маніпулювати вмістом, структурою та стилями сторінки. Давайте розберемося як це влаштовано та як це працює.

Як будується веб-сторінка?

Процес перетворення вихідного HTML-документа в стилізовану та інтерактивну сторінку, що відображається, називається “Critical Rendering Path” (“Критичним шляхом рендерингу”). Хоча цей процес можна розбити на кілька етапів, як я описав це у статті «Розуміння критичного шляху рендерингу», ці етапи можна умовно згрупувати у два етапи. У першому браузер аналізує документ, щоб визначити, що зрештою відображатиметься на сторінці, а в другому браузер виконує рендеринг.

Результатом першого етапу і те, що називається “render tree” («дерево рендеринга»). Дерево рендерингу – це представлення елементів HTML, які відображатимуться на сторінці та пов'язаних з ними стилів. Щоб збудувати це дерево, браузеру потрібні дві речі:

  • CSSOM, представлення стилів, пов'язаних з елементами
  • DOM, представлення елементів
  • З чого складається DOM?

    DOM – це об'єктне уявлення вихідного HTML-документа. Він має деякі відмінності, як ми побачимо нижче, але, по суті, це спроба перетворити структуру та зміст документа HTML в об'єктну модель, яка може використовуватися різними програмами.

    Структура об'єктів DOM представлена ​​тим, що називається "деревом вузлів". Воно так називається, тому що його можна розглядати як дерево з одним батьківським елементом, що розгалужується на кілька дочірніх гілок, кожна з яких може мати листя. І тут батьківський «елемент» – це кореневий елемент, дочірні «гілки» – це вкладені елементи, а «листя» – це вміст усередині елементів.

    Давайте розглянемо цей HTML-документ як приклад:

    My first web page Hello, world!

    How are you?

    Цей документ може бути поданий у вигляді наступного дерева вузлів:

    • html
      • head
        • title
          • My first web page
      • body
        • h1
          • Hello, world!
        • p
          • How are you?
    Чим DOM не є

    У наведеному прикладі здається, що DOM є відображенням 1: 1 вихідного HTML-документа. Однак, як я вже казав, є різницю. Щоб повністю зрозуміти, що таке DOM, нам потрібно поглянути на те, чим він не є.

    DOM не є копією вихідного HTML

    Хоча DOM створений з HTML-документа, він не завжди такий самий. Є два випадки, коли DOM може відрізнятися від вихідного HTML.

    1. Коли HTML містить помилки розмітки

    DOM – це інтерфейс доступу до дійсних (тобто вже відображених) елементів документа HTML. У процесі створення DOM браузер сам може виправити деякі помилки в коді HTML.

    Розглянемо як приклад цей HTML-документ:

    Hello, world!

    У документі відсутні елементи та , що є обов'язковою вимогою для HTML. Але якщо ми подивимося на дерево, що вийшло DOM, то побачимо, що це було виправлено:

    • html
      • head
      • body
        • Hello, world!
      2. Коли DOM модифікується кодом Javascript

      Крім того, що DOM є інтерфейсом для перегляду вмісту документа HTML, він також може бути змінений.

      Наприклад, ми можемо створити додаткові вузли для DOM, використовуючи Javascript.

      Var NewParagraph = document.createElement("p"); var paragraphContent = document.createTextNode("I"m new!");newParagraph.appendChild(paragraphContent);

      Цей код змінить DOM, але зміни не з'являться у документі HTML .

      DOM – це не те, що ви бачите у браузері (тобто дерево рендерингу)

      У вікні перегляду браузера ви бачите дерево рендерингу, яке є комбінацією DOM і CSSOM. Чим відрізняється DOM від дерева рендерингу, так це те, що останнє складається тільки з того, що зрештою буде відображено на екрані.

      Оскільки дерево рендерингу стосується лише того, що відображається, воно виключає елементи, які візуально приховані. Наприклад, елементи, які мають стилі з display: none .

      Hello, world!

      How are you?

      DOM включатиме елемент

      • html
        • head
        • body
          • h1
            • Hello, world!
          • p
            • How are you?

      Однак дерево рендерингу і, отже, те, що видно у вікні перегляду, не буде включено до цього елемента.

      • html
        • body
          • h1
            • Hello, world!
      DOM – це не те, що відображається у DevTools

      Ця різниця трохи менша, тому що інспектор елементів DevTools забезпечує найближче наближення до DOM, яке ми маємо в браузері. Однак інспектор DevTools містить додаткову інформацію, якої немає у DOM.

      Найкращий приклад цього – псевдоелементи CSS. Псевдоелементи, створені з використанням селекторів ::before та ::after , є частиною CSSOM та дерева рендерингу, але технічно не є частиною DOM. Це пов'язано з тим, що DOM створюється лише з вихідного документа HTML, не включаючи стилі, застосовані до елемента.

      Незважаючи на те, що псевдоелементи не є частиною DOM, вони є в нашому інспекторі елементів devtools.


      Резюме

      DOM – це інтерфейс HTML-документа. Він використовується браузерами як перший крок до визначення того, що візуалізувати у вікні перегляду, та кодом Javascript для зміни вмісту, структури чи стилю сторінки.

    Дана публікація передує ряду статей про альтернативні способи роботи з XML. "Альтернативних", тому що зазвичай робота з XML в 1С обмежується аналізом xml за допомогою послідовного читання - рядкового аналізу текстового вмісту. Адже є ще й інші способи.

    Наприклад, використання мови запитів до XML xPath або шаблонів трансформації XSL . Про ці варіанти буде розказано у наступних статтях. Але вони спираються на базове представлення документів XML як DOM . Про те, що таке DOM (document object model або об'єктна модель документа) і йтиметься у публікації.

    DOM базується на поданні документа будь-якої структури у вигляді дерева вузлів, кожен вузол (нода) якого є елементом, атрибутом елемента, текстовим значенням елемента тощо. Зв'язок між вузлами побудований за принципом "батько - підлеглі". У кореня документа (дерева DOM) батька немає. У тупикового елемента немає підлеглого (такі елементи абстрактно називаються листям дерева). Таким чином, модель DOM може створюватися не тільки для XML, але фактично для будь-якого структурованого документа (HTML, XHTML). Так, наприклад, браузер користувача, отримуючи HTML код веб-сторінки з Інтернету, будує дерево DOM цієї сторінки в оперативній пам'яті комп'ютера користувача.

    Модель DOM відкриває широкі можливості для маніпуляції даними документа. Можна створювати нові вузли, вставляти їх на різних рівнях дерева, копіювати вузли, видаляти вузли, шукати вузли за різними параметрами та багато іншого.

    Модель DOM документа XML наочно представлена ​​нижче.

    Будь-яка сучасна мова програмування має у своєму складі засоби (парсери) для роботи з таким деревом. Отримуючи на вхід рядковий вміст XML-парсер, вибудовує в оперативній пам'яті дерево вузлів і виконує маніпуляції з даними дерева. Перевага такого підходу перед рядковим розбором очевидна: одним запитом до дерева можна вибрати необхідні дані, не перебираючи весь документ, оскільки в оперативній пам'яті знаходиться повне представлення елементів з усіма взимкомсвязями.

    У платформі 1С модель DOM представлена ​​спеціальним об'єктом Документ DOM , який у свою чергу будується за допомогою об'єкта Побудователь DOM та його методу Прочитати . На вхід цього методу, як правило, подається або об'єкт Читання XML або Читання HTML, за допомогою яких здійснюється безпосереднє зчитування з файлів або завантаження з рядка текстового вмісту XML або HTML. Ну і далі є низка конструкцій, що дозволяють витягувати дані з об'єктної моделі прочитаного документа.

    З усіх варіантів найцікавішим з моєї точки зору є варіант №1 з використанням методу Обчислити Вираз XPath. Йому буде присвячено таку статтю.

    Плюси рядкового аналізу: потреба в ресурсах менша. Мінуси: довго за часом, щоб отримати дані потрібно прочитати весь файл, складність програмного коду при розборі XML-документів зі складною структурою.

    Перевага вибірки через DOM: швидкість вибірки даних, простота програмного коду. Мінуси: вимогливість до ресурсів, на побудову та запити до DOM витрачається оперативна пам'ять та процесорні потужності.