DOM (Document Object Model)

DOM (Document Object Model, «объектная модель документа») — это независящий от платформы и языка программный интерфейс (API), позволяющий программам и скриптам получить доступ к содержимому HTML, XHTML и XML-документов, а также изменять содержимое, структуру и оформление таких документов.

DOM - это модель документа, загруженная в браузер и представляющая документ как иерархическую совокупность узлов дерева, где каждый узел представляет часть документа (например, элемент, атрибут, строку текста или комментарий, и т.д.). Узлы DOM связаны между собой отношениями «родительский-дочерний».

DOM позволяет:

  1. создавать, перемещать и изменять узлы DOM;
  2. добавлять к узлам DOM обработчики событий, которые срабатывают при наступлении какого-либо события. 

Спецификация DOM

Веб-браузеры не обязаны использовать DOM, чтобы исполнять HTML-документ. Однако DOM требуется для скриптов JavaScript, которые могут отслеживать или изменять веб-страницу динамически. Другими словами, Document Object Model — это инструмент, с помощью которого JavaScript видит содержимое HTML-страницы и состояние браузера.

Учитывая существование различных реализаций DOM в веб-браузерах, целесообразно проверять работоспособность тех или иных возможностей DOM для каждого конкретного браузера и только потом использовать их.

Пример

[свернуть]

Основой HTML-документа являются теги, которые в соответствии с объектной моделью документа DOM являются объектами и, соответственно, доступны при помощи JavaScript и могут использоваться для изменения страницы.

Вложенные теги являются дочерними элементами родительского тега (текст, который находится внутри тега, также является объектом).

Узлы DOM (дерево тегов)

Читай также DOM-дерево

DOM – это представление документа в виде дерева узлов, имеющих родителя и дочерние узлы. 

Каждый узел этого дерева – это объект, поэтому, как и любой объект в JavaScript, он может содержать пользовательские свойства и методы, например:

Пользовательские (нестандартные) свойства и методы элементов видны только в JavaScript и никак не влияют на отображение соответствующего тега.

Все, что есть, например, в HTML (в т.ч. объект document, <!DOCTYPE...>, теги, комментарии и т.п.), является частью DOM.

Согласно спецификации существует 12 типов узлов DOM, но на практике в основном работают со следующими:

  • document – «входная точка» в DOM (подробнее...);
  • узлы-элементы (HTML-теги, основные строительные блоки);
  • текстовые узлы;
  • комментарии (включают информацию, которая не будет показана, но доступна в DOM для чтения JS).

Элемент DOM - это узел, который объявлен с использованием тега в HTML-документе (например, <html>, <head>,<body> и т.д.).

Т.о. теги являются узлами-элементами (или просто элементами). Они образуют структуру дерева:

  • <html> – это корневой узел;
  • <head> и <body> - дочерние узлы тега <html> и т.д.;
  • текст внутри элементов образует текстовые узлы (#text).

Особенности текстового узла DOM:

  1. содержит в себе только строку текста;
  2. не имеет потомков (находится всегда на самом нижнем уровне);
  3. специальные символы в текстовых узлах (перевод строки или \n, а также пробел ) являются полноправными текстовыми символами, образуют текстовые узлы и становятся частью дерева DOM;
  4. по историческим причинам пробелы и перевод строки перед тегом <head> игнорируются;
  5. после закрывающего тега </body> не может быть никаких пробелов (если мы записываем что-либо после закрывающего тега </body>, браузер автоматически перемещает эту запись в конец body, поскольку спецификация HTML требует, чтобы всё содержимое было внутри <body>).

При работе с деревом DOM с использованием инструментов разработчика в браузере пробелы в начале (конце) текста и пустые текстовые узлы (переносы строк) между тегами обычно не отображаются.

Если браузер сталкивается с некорректно написанным HTML-кодом, он автоматически корректирует его при построении DOM.

Например, при генерации DOM браузер самостоятельно обрабатывает ошибки в документе и добавляет или закрывает теги, если в начале документа нет тега <html>, то он будет создан браузером в дереве DOM (то же касается и тега <body>), или когда браузер впервые сталкивается с элементом, который не должен быть в <head>, например, с тегом <H2>, он закрывает <head> и вместо этого запускает body.

Иерархия узлов DOM

DOM позволяет изменять его элементы и содержимое, но для начала нужно получить соответствующий DOM-объект.

Нельзя получить доступ к элементу, которого ещё не существует в момент выполнения скрипта; в DOM значение null - «узел не существует».

Иерархия DOM:

  • объект document (главная «точка входа» в DOM, из него можно получить доступ к любому узлу), самые верхние элементы дерева DOM доступны как свойства объекта document:
    • <html> = document.documentElement;
      • <body> = document.body;
      • <head> = document.head.

Виды дочерних узлов DOM:

  1. Дочерние узлы – узлы DOM, которые являются прямыми дочерними элементами узла (например, <head> и <body> - дочерние узлы элемента <html>).
  2. Потомки – все узлы DOM, которые лежат внутри узла, т.е. как прямые дочерние узлы, так и вложенные в них (например, <head> и <title> - потомки элемента <html>).
  3. Соседи – это узлы, у которых один и тот же родитель (например, <head> и <body> - дочерние элементы и соседи внутри элемента <html>).

Доступ к узлам DOM

Нахождение заданного узла

Свойство Node.nodeName (имя текущего узла)

Свойство только для чтения Node.nodeName возвращает имя текущего узла в виде строки.

Возвращаемое значение для различных типов узлов

Синтаксис:

где nodeName - это имя текущего узла node.

Пример:

В XHTML (или любых других форматов XML), значение text_field будет прочитано как div (в нижнем регистре). Свойства nodeName и tagName возвращают имена элементов HTML в DOM, помеченном как HTML документ, в верхнем регистре (подробнее...).

Свойство tagName можно было бы использовать вместо nodeName, однако для текстового узла:

  • nodeName возвращает #text ,
  • tagName возвращает undefined.

[свернуть]
Свойство parentNode (родительский узел элемента DOM)

Свойство parentNode возвращает:

  • родителя определённого элемента DOM дерева;
  • null - если узел не имеет родителя;
  • null  - если элемент только был создан и ещё не добавлен в DOM-дерево.

Синтаксис:

где

  • parentNode - ссылка на родительский узел текущего элемента (родитель элемента имеет тип Element, Document или DocumentFragment).

Пример:

[свернуть]
Свойство childNodes (коллекция (NodeList) дочерних элементов узла)

Доступный для чтения атрибут Node.childNodes возвращает живую (динамическую) коллекцию (NodeList) дочерних узлов (не потомков!) узла Node, включая элементы, текст и комментарии.

Синтаксис:

где node.childNodes - упорядоченная коллекция объектов элементов (тип этого списка - NodeList), которые являются дочерними для элемента node. Если у элемента node нет дочерних, то node.childNodes пуст.

Несмотря на то, что NodeList не является массивом (Array), его можно перебрать при помощи метода forEach(). NodeList также можно конвертировать в Array при помощи метода Array.from().

Пример ниже последовательно выведет дочерних элементов document.body:

Если запустить пример выше, то последним будет выведен элемент <script>, несмотря на то, что в документе есть ещё «...HTML-код 2...». На момент выполнения скрипта браузер ещё до элемента «...HTML-код 2...» не дошёл, поэтому скрипт его не выведет.

[свернуть]
Свойство Element.children (коллекция (HTMLCollection) дочерних элементов узла)

Свойство Element.children, доступное только для чтения, возвращает живую (динамическую) коллекцию (HTMLCollection), которая содержит все дочерние элементы узла Element.

Если элемент не имеет дочерних элементов, дочерние элементы представляют собой пустой список длиной 0.

Element.children включает только узлы элементов. Чтобы получить все дочерние узлы, включая узлы, не являющиеся элементами, например узлы текста и комментариев, используйте Node.childNodes.

Синтаксис:

где

  • collection - упорядоченная коллекция (HTMLCollection) элементов DOM, которые являются дочерними элементами узла node.

Вы можете получить доступ к отдельным дочерним узлам в коллекции, используя метод item() в коллекции или используя скобочную нотацию в стиле массива JavaScript:

[свернуть]
Метод hasChildNodes (проверка наличия дочерних узлов)

Метод node.hasChildNodes() возвращает Boolean значение, показывающее имеет ли текущий узел node дочерние узлы или нет.

Синтаксис:

[свернуть]
Метод querySelector( ) (нахождение первого заданного узла)

 Метод Document.querySelector() возвращает:

  • первый элемент (Element) документа, который соответствует указанному в аргументе селектору или группе селекторов;
  • null - если совпадений не найдено.

Сопоставление аргумента с узлами DOM выполняется с использованием последовательного обхода всех узлов документа в глубину, начиная с первого элемента в разметке документа.

Синтаксис:

где

  • element - ссылка на объект типа Element, являющийся первым элементом DOM, который соответствует указанному в аргументе селектору (группе селекторов) selectors;
  • selectors - строка DOMString, содержащая один или более селекторов для сопоставления (если не является допустимой строкой селектора CSS, то генерируется исключение SYNTAX_ERR). 

Пример:

Если вам нужен список всех элементов, соответствующих указанным селекторам, используйте метод querySelectorAll():

Пример

[свернуть]

Символы, которые не являются частью стандартного синтаксиса CSS должны быть экранированы символом обратной косой черты. Поскольку JavaScript также использует экранирование символом обратной косой черты, будьте особенно внимательны при написании строковых литералов с использованием этих символов (подробнее...).

Псевдо-элементы CSS никогда не вернут никаких элементов, как указано в API селекторов.

[свернуть]
Метод querySelectorAll( ) (нахождение всех узлов, соответствующих критерию)

Метод Document.querySelectorAll() возвращает статическую (неживую) коллекцию (NodeList), содержащую все найденные элементы документа, которые соответствуют указанному в аргументе метода селектору.

Синтаксис:

где

  • elementList - статический (non-live) NodeList, содержащий все элементы в пределах документа, которые соответствуют как минимум одному из указанных селекторов selectors, или пустой NodeList в случае отсутствия совпадений указанному в аргументе селектору (группе селекторов) selectors;
  • selectors - строка DOMString, содержащая один или более селекторов для сопоставления (если не является допустимой строкой селектора CSS, то генерируется исключение SYNTAX_ERR); несколько селекторов разделяются запятыми.

Символы, которые не являются частью стандартного синтаксиса CSS должны быть экранированы символом обратной косой черты. Поскольку JavaScript также использует экранирование символом обратной косой черты, будьте особенно внимательны при написании строковых литералов с использованием этих символов (подробнее...).

Если в строке selectors содержатся CSS псевдоэлементы, то возвращаемый список будет всегда пуст.

Пример:

[свернуть]

Работа только с узлами-элементами

Учитывают только узлы-элементы:

  • children – коллекция (HTMLCollection) элементов DOM, которые являются дочерними элементами узла;
  • firstElementChild, lastElementChild – первый и последний дочерний элемент;
  • previousElementSibling, nextElementSibling – соседи-элементы;
  • parentElement – родитель-элемент.
Исключение document.documentElement.parentElement

Причина в том, что родителем корневого узла document.documentElement (<html>) является document. Но document – это не узел-элемент, так что parentNode его вернёт, а parentElement - нет.

[свернуть]

Навигация по узлам внутри родительского узла

Свойства firstChild и lastChild (первый и последний потомок узла)

Свойство только для чтения Node.firstChild возвращает:

  • первый потомок узла в древе или
  • null, если узел является бездетным.

Если узел это документ, он возвращает первый узел в списке своих прямых дочерних элементов.

Синтаксис:

где childNode - это ссылка на первый потомок узла node, если таковой имеется, в противном случае - null.

Примеры (обратите внимание на обработку пробелов как текстовых узлов):

Любое пустое пространство  между узлами (в т.ч. единичный пробел, разрыв строки, отступ и т. д.) является причиной вставки узла #text.

Если эти пробелы удаляются из источника, узлы #text не вставляются и элемент span становится первым потомком абзаца <p id="myNode">.

Свойства nodeName и tagName возвращают имена элементов HTML в DOM, помеченном как HTML документ, в верхнем регистре (подробнее...).

Свойство lastChild возвращает последнего потомка в узле.

Возвращаемый элемент last_child является последним потомком узла node. Если в опрашиваемом узле node нет дочерних элементов, node.lastChild  возвращает null .

Если у тега есть дочерние узлы, условие ниже всегда верно:

[свернуть]
Свойства nextSibling и previousSibling (следующий и предыдущий узел)

Свойство Node.nextSibling используется только для чтения и возвращает:

  • узел, непосредственно следующий за данным узлом в списке childNodes его родительского элемента, или
  • null, если данный узел последний в этом списке.

Свойство Node.previousSibling используется только для чтения и возвращает:

  • узел, предшествующий указанному в родительском элементе childNodes, или
  • null, если указанный узел первый в своём родителе.

Синтаксис:

Браузеры, основанные на Gecko, вставляют текстовые узлы в документ для представления пробелов в разметке. Поэтому узел, полученный, например, при использовании Node.firstChild или Node.previousSibling может относиться к пробелу, а не к тому элементу, который вы хотели бы получить.

[свернуть]

Удаление узлов или элементов DOM

Методы removeChild и remove() (удаление элемента DOM)

Метод removeChild() удаляет дочерний элемент, переданный в аргумент метода, из DOM и возвращает удалённый элемент.

Синтаксис:

где 

  • child - дочерний элемент который будет удалён из DOM;
  • node - родительский узел удаляемого child;
  • oldChild - переменная, в которую передана ссылка на удаляемый дочерний элемент (oldChild === child).

Удалённый дочерний элемент остаётся в памяти, но больше не является частью DOM. Вы можете повторно использовать удалённый элемент с помощью ссылки.

Метод генерирует исключение в случае:

  1. если child не является дочерним элементом node;
  2. если child являлся дочерним элементом node во время вызова метода, но был удалён во время вызова обработчика событий удаляющего элемент (т.e при удалении элемента непосредственно перед вызовом обработчика событий).

Метод Element.remove() удаляет элемент Element из DOM-дерева, в котором он находится.

Примеры удаления всех потомков в узле:

Удаление элемента с известным родительским узлом:

Удаление элемента без указания его родителя:

Удаление всех дочерних элементов выбранного узла:

Удаление элемента коллекции NodeList с заданным номером:

[свернуть]
Очистка HTML от заданных тегов

[свернуть]

Добавить комментарий

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.