3.4. DOM — объектная модель документа
DOM была придумана создателями браузеров. Консорциум World Wide Web Consortium (W3C) стандартизировал DOM как единую спецификацию.
W3C определяет DOM как «интерфейс, не зависящий от платформы и языка, который позволяет программам и сценариям динамически получать доступ к содержимому и структуре документов и обновлять их». То есть, данная модель не предоставляет конкретную реализацию, а лишь описывает объекты, свойства, методы.
Концепция DOM реализована с разной степенью поддержки во всех основных браузерах. С помощью объектной модели документа можно создавать документы, перемещаться по их структуре, а также добавлять, изменять или удалять элементы и содержимое.
Когда пользователь запрашивает определенную веб-страницу, механизм рендеринга начинает получать HTML, CSS и JS-файлы запрошенной веб-страницы через сетевой уровень. После получения содержимого страницы, HTML и CSS-файлы анализируются по частям. Узлы DOM создаются для формирования дерева DOM и дерева CSSOM.
Дерево визуализации создается путем объединения деревьев DOM и CSSOM. Дерево визуализации содержит как информацию о порядке элементов, так и информацию об их стиле. На этом этапе каждому узлу присваиваются специальные координаты, чтобы гарантировать, что каждый элемент отображается в одном и том же положении на экране. После чего выполняется обход дерева визуализации, и каждый узел, упомянутый в дереве, отображается на экране.
- Содержание:
- 1. Введение в DOM
- 2. Интерфейсы и узлы DOM
- 3. Свойства узлов
- 3.1. Определение типа и имени узла: свойства nodeName и nodeType
- 3.2. Получение значения узла: свойство nodeValue
- 3.3. Отношения между узлами
- 3.3.1. Свойство childNodes
- 3.3.2. Свойство parentNode
- 3.3.3. Свойства previousSibling и nextSibling
- 3.3.4. Свойства firstChild и lastChild
- 3.3.5. Свойство parentElement
- 3.3.6. Свойство ownerDocument
- 3.4. Другие свойства узлов: baseURI, isConnected и textContent
- 4. Манипуляции узлами
- 4.1. Создание новых узлов
- 4.1.1. Метод appendChild()
- 4.1.2. Метод cloneNode()
- 4.1.3. Метод insertBefore()
- 4.1.4. Метод replaceChild()
- 4.1.5. Метод removeChild()
- 4.2. Проверка позиции узла в дереве DOM: методы compareDocumentPosition() и contains()
- 4.3. Определение идентичности узлов с помощью метода isEqualNode()
- 4.4. Определение отношений между узлами
- 5. Пространства имен XML: методы ookupNamespaceURI(), isDefaultNamespace() и lookupPrefix()
- 6. Объединение родственных текстовых узлов в один с помощью метода normalize()
1. Введение в DOM
DOM — это API для HTML и XML-документов. API расшифровывается как интерфейс прикладного программирования, который можно определить как совокупность способов связи между различными компонентами программного обеспечения. Другими словами, API позволяет одной программе взаимодействовать с другой.
Спецификация DOM определяет набор интерфейсов для доступа и управления объектами HTML и XML-документов. Интерфейсы являются абстракцией, средствами определения способа доступа и управления внутренними представлениями документа в приложении.
Согласно терминологии W3C DOM, каждый документ представлен в виде дерева, а каждый автономный элемент или текстовый блок известен как узел — фундаментальный строительный блок. Термин «узел» происходит из сети, где он используется для обозначения точки подключения, и сама сеть представляет собой набор узлов. Узлы имеют отношения родитель-потомок, когда один контейнер содержит другой. Узел — это общее имя для объекта любого типа в иерархии DOM.
Когда происходит загрузка соответствующей страницы, в памяти браузера реализуется поддержка структуры объектов, сгенерированных согласно использованным в документе HTML-тегам. У каждого узла есть родительский узел (за исключением корневого узла document) и любое количество дочерних узлов. Одни типы узлов могут иметь дочерние узлы различных типов, другие являются так называемыми листовыми узлами, у которых не может дочерних узлов. Дерево состоит из узлов, но только некоторые из них являются HTML-элементами.
Узлы не представляют структуру данных, они представляют объекты, которые имеют функции и идентичность. В объектно-ориентированных языках программирования данные инкапсулируются в объекты, которые скрывают данные, защищая их от прямых внешних манипуляций. Функции, связанные с этими объектами, определяют, как ими можно манипулировать.
2. Интерфейсы и узлы DOM
Ядро DOM API состоит из Node, Element, Document и других относительно универсальных интерфейсов. Стандарт DOM также включает интерфейсы, специфичные как для HTML-документов, так и тегов многих HTML-элементов. Эти интерфейсы, например, HTMLBodyElement, HTMLTitleElement, обычно определяют набор свойств, отражающих атрибуты тега, которые обеспечивают удобный доступ к значениям атрибутов.
Базовый интерфейс, от которого наследуются все интерфейсы HTML-элементов и который должен использоваться элементами, не имеющими дополнительных атрибутов, — это интерфейс HTMLElement.
Элемент(ы) | Интерфейс(ы) |
---|---|
<a> | HTMLAnchorElement : HTMLElement |
<abbr> | HTMLElement |
<address> | HTMLElement |
<area> | HTMLAreaElement : HTMLElement |
<article> | HTMLElement |
<aside> | HTMLElement |
<audio> | HTMLAudioElement : HTMLMediaElement : HTMLElement |
<b> | HTMLElement |
<base> | HTMLBaseElement : HTMLElement |
<bdi> | HTMLElement |
<bdo> | HTMLElement |
<blockquote> | HTMLQuoteElement : HTMLElement |
<body> | HTMLBodyElement : HTMLElement |
<br> | HTMLBRElement : HTMLElement |
<button> | HTMLButtonElement : HTMLElement |
<canvas> | HTMLCanvasElement : HTMLElement |
<caption> | HTMLTableCaptionElement : HTMLElement |
<cite> | HTMLElement |
<code> | HTMLElement |
<col> | HTMLTableColElement : HTMLElement |
<colgroup> | HTMLTableColElement : HTMLElement |
<data> | HTMLDataElement : HTMLElement |
<datalist> | HTMLDataListElement : HTMLElement |
<dd> | HTMLElement |
<del> | HTMLModElement : HTMLElement |
<details> | HTMLDetailsElement : HTMLElement |
<dfn> | HTMLElement |
<dialog> | HTMLDialogElement : HTMLElement |
<div> | HTMLDivElement : HTMLElement |
<dl> | HTMLDListElement : HTMLElement |
<dt> | HTMLElement |
<em> | HTMLElement |
<embed> | HTMLEmbedElement : HTMLElement |
<fieldset> | HTMLFieldSetElement : HTMLElement |
<figcaption> | HTMLElement |
<figure> | HTMLElement |
<footer> | HTMLElement |
<form> | HTMLFormElement : HTMLElement |
<h1> — <h6> | HTMLHeadingElement : HTMLElement |
<head> | HTMLHeadElement : HTMLElement |
<header> | HTMLElement |
<hgroup> | HTMLElement |
<hr> | HTMLHRElement : HTMLElement |
<html> | HTMLHtmlElement : HTMLElement |
<i> | HTMLElement |
<iframe> | HTMLIFrameElemen : HTMLElement |
<img> | HTMLImageElement : HTMLElement |
<input> | HTMLInputElement : HTMLElement |
<ins> | HTMLModElement : HTMLElement |
<kbd> | HTMLElement |
<label> | HTMLLabelElement : HTMLElement |
<legend> | HTMLLegendElement : HTMLElement |
<li> | HTMLLIElement : HTMLElement |
<link> | HTMLLinkElement : HTMLElement |
<main> | HTMLElement |
<map> | HTMLMapElement : HTMLElement |
<mark> | HTMLElement |
<menu> | HTMLMenuElement : HTMLElement |
<meta> | HTMLMetaElement : HTMLElement |
<meter> | HTMLMeterElement : HTMLElement |
<nav> | HTMLElement |
<noscript> | HTMLElement |
<object> | HTMLObjectElement : HTMLElement |
<ol> | HTMLOListElement : HTMLElement |
<optgroup> | HTMLOptGroupElement : HTMLElement |
<option> | HTMLOptionElement : HTMLElement |
<output> | HTMLOutputElement : HTMLElement |
<p> | HTMLParagraphElement : HTMLElement |
<param> | HTMLParamElement : HTMLElement |
<picture> | HTMLPictureElement : HTMLElement |
<pre> | HTMLPreElement : HTMLElement |
<progress> | HTMLProgressElement : HTMLElement |
<q> | HTMLQuoteElement : HTMLElement |
<rp> | HTMLElement |
<rt> | HTMLElement |
<ruby> | HTMLElement |
<s> | HTMLElement |
<samp> | HTMLElement |
<script> | HTMLScriptElement : HTMLElement |
<section> | HTMLElement |
<select> | HTMLSelectElement : HTMLElement |
<slot> | HTMLSlotElement : HTMLElement |
<small> | HTMLElement |
<source> | HTMLSourceElement : HTMLElement |
<span> | HTMLSpanElement : HTMLElement |
<strong> | HTMLElement |
<style> | HTMLStyleElement : HTMLElement |
<sub> | HTMLElement |
<summary> | HTMLElement |
<sup> | HTMLElement |
<table> | HTMLTableElement : HTMLElement |
<tbody> | HTMLTableSectionElement : HTMLElement |
<td> | HTMLTableCellElement : HTMLElement |
<template> | HTMLTemplateElement : HTMLElement |
<textarea> | HTMLTextAreaElement : HTMLElement |
<tfoot> | HTMLTableSectionElement : HTMLElement |
<th> | HTMLTableCellElement : HTMLElement |
<thead> | HTMLTableSectionElement : HTMLElement |
<time> | HTMLTimeElement : HTMLElement |
<title> | HTMLTitleElement : HTMLElement |
<tr> | HTMLTableRowElement : HTMLElement |
<track> | HTMLTrackElement : HTMLElement |
<u> | HTMLElement |
<ul> | HTMLUListElement : HTMLElement |
<var> | HTMLElement |
<video> | HTMLVideoElement : HTMLMediaElement : HTMLElement |
<wbr> | HTMLElement |
Интерфейс Node (который в свою очередь реализует интерфейс EventTarget) является основным типом данных для всей объектной модели документа. Node представляет собой абстрактный интерфейс и не существует как узел. Он используется всеми узлами — Document, DocumentType, DocumentFragment, Element, Text, Attr, CDATASection, ProcessingInstruction и Comment.
Хотя все объекты, реализующие интерфейс Node, предоставляют методы для работы с потомками, не все объекты, реализующие интерфейс Node, могут иметь потомков (например, текстовые узлы).
3. Свойства узлов
Все объекты узлов, например, Element, Text и т.д., наследуют свойства и методы от интерфейса Node. Эти свойства и методы являются базовыми значениями и функциями для управления, проверки и обхода DOM.
Многие свойства DOM доступны только для чтения. Это означает, что их можно использовать для получения информации, но не для ее установки или обновления.
3.1. Определение типа и имени узла: свойства nodeName и nodeType
У объектов Node есть свойства идентификации, такие как nodeName и nodeType.
Интерфейс | nodeType | Значение nodeName |
---|---|---|
Element | Node.ELEMENT_NODE (1) | полное имя HTML-тега в верхнем регистре |
Attr | Node.ATTRIBUTE_NODE (2) | полное имя атрибута |
Text | Node.TEXT_NODE (3) | #text |
CDATASection | Node.CDATA_SECTION_NODE (4) | #cdata-section |
ProcessingInstruction | Node.PROCESSING_INSTRUCTION_NODE (7) | имя, определяющее приложение, для которого предназначена инструкция |
Comment | Node.COMMENT_NODE (8) | #comment |
Document | Node.DOCUMENT_NODE (9) | #document |
DocumentType | Node.DOCUMENT_TYPE_NODE (10) | название типа документа |
DocumentFragment | Node.DOCUMENT_FRAGMENT_NODE (11) | #document-fragment |
<!DOCTYPE html>
<html lang="ru">
<body>
<p class="example">Какой-то текст</a>
</body>
</html>
Свойство nodeName возвращает имя/название в виде строки, либо постоянное значение (которому предшествует символ #). Используется только для чтения.
console.log(document.doctype.nodeName)); // html
console.log(document.nodeName); // #document
console.log(document.body.nodeName); // BODY
console.log(document.createDocumentFragment().nodeName); // #document-fragment
console.log(document.querySelector('p').nodeName); // P
console.log(document.querySelector('p').firstChild.nodeName); // #text
console.log(document.querySelector('p').nodeType === 1); // true
Свойство nodeType возвращает целочисленный идентификатор типа узла. Интерфейс Node содержит константы, которые соответствуют этим числам. Определение типа узла полезно в сценариях, когда перебирается неизвестный набор узлов. Определение типа узла, для которого вы можете написать сценарий, может быть очень удобным, если вы хотите знать, какие свойства и методы доступны для сценария узла.
console.log(document.doctype.nodeType); // 10
console.log(document.nodeType); // 9
console.log(document.createDocumentFragment().nodeType); // 11
console.log(document.querySelector('p').nodeType); // 1
console.log(document.querySelector('p').firstChild.nodeType);// 3
3.2. Получение значения узла: свойство nodeValue
Свойство nodeValue возвращает или устанавливает значение узла.
Для большинства типов узлов возвращает null и любой набор операций игнорируется. Для узлов типа TEXT_NODE, COMMENT_NODE, CDATA_SECTION_NODE и PROCESSING_INSTRUCTION_NODE, значение соответствует текстовым данным, содержащимся в объекте. Для узла ATTRIBUTE_NODE вернет значение атрибута.
Использование данного свойства полезно для извлечения текстовых строк из узлов Text и Comment.
console.log(document.doctype.nodeValue); // null
console.log(document.nodeValue); // null
console.log(document.createDocumentFragment().nodeValue); // null
console.log(document.querySelector('p').nodeValue); // null
console.log(document.querySelector('p').firstChild.nodeValue); // Какой-то текст
3.3. Отношения между узлами
Все узлы в документе имеют связи с другими узлами. Эти отношения описываются в терминах традиционных семейных отношений, как если бы дерево документа было генеалогическим древом.
<ul id="list">
<li>Пункт 1</li>
<li>Пункт 2</li>
<li><a href="https://google.com">Пункт 3</a></li>
<li>Пункт 4</li>
</ul>
3.3.1. Свойство childNodes
Каждый узел имеет свойство childNodes, которое извлекает все дочерние узлы объекта и сохраняет их возвращает живой NodeList, содержащий всех потомков данного узла. Свойство используется только для чтения. Живой NodeList означает то, что если потомки узла изменяются, объект NodeList автоматически обновляется. NodeList — это объект типа массива, используемый для хранения упорядоченного списка узлов, доступных по позиции. NodeList не является экземпляром Array. Вы можете получить доступ к дочернему элементу текущего элемента через счетчик массива или метод item().
const elem = document.getElementById('list');
const count = elem.childNodes.length;
const firstChild = elem.childNodes.item(0);
console.log(count); // 9
console.log(firstChild); // [object Text]
Когда DOM конструируется браузером, текстовые узлы создаются как из пробелов, так и из текстовых символов, поэтому в данном примере каждый символ разрыва строки считается как текстовый узел.
3.3.2. Свойство parentNode
Каждый узел имеет свойство parentNode, указывающее на его родителя в дереве документа. Свойство возвращает ссылку на внешний узел, который отражается как объект, принадлежащий документу. Все узлы, содержащиеся в списке дочерних узлов, имеют одного и того же родителя, поэтому каждое из их свойств родительского узла указывает на один и тот же узел. Если нет такого узла, по причине того, что узел находится вверху дерева или не относится к дереву, данное свойство вернет null. Свойство parentNode текстового фрагмента — это внешний узел или элемент, охватывающий этот фрагмент.
const elem = document.getElementById('list');
const parentElem = elem.parentNode;
document.write(parentElem); // [object HTMLBodyElement]
3.3.3. Свойства previousSibling и nextSibling
Можно переходить от одного узла в списке к другому, используя свойства previousSibling и nextSibling. Свойства используются только для чтения.
Свойство previousSibling возвращает узел, представляющий предыдущий одноуровневый узел в дереве или null, если не такого узла.
Свойство nextSibling возвращает узел, представляющий следующий одноуровневый узел в дереве или null, если не такого узла.
Первый узел в списке имеет значение null для его свойства previousSibling, а последний узел в списке имеет значение null для его свойства nextSibling.
const list = document.querySelector('ul');
console.log(list.nextSibling.nodeName); // #text
console.log(list.previousSibling.nodeName); // #text
3.3.4. Свойства firstChild и lastChild
Свойства firstChild и lastChild возвращают узел, представляющий первый или последний потомок узла в дереве или null, если узел не имеет потомков. Свойства используются только для чтения. Они полезны, когда вы хотите вставить новый дочерний элемент до или после всех остальных, и вам нужна точка отсчета для методов, которые добавляют элементы в список узлов документа.
<p id="p1"></p>
<p id="p2"> </p>
console.log(document.getElementById('p1').firstChild); // null
console.log(document.getElementById('p2').lastChild.nodeName); // #text
3.3.5. Свойство parentElement
Свойство parentElement возвращает элемент, который является родителем данного узла. Если узел не имеет родителя или если родитель не элемент, это свойство вернет null. Свойство работает только с элементами HTML, которые отражаются как объекты документа, тогда как узел не обязательно является элементом HTML (например, атрибутом или текстовым фрагментом). Используется только для чтения.
<ul id="list">
<li>Пункт 1</li>
<li>Пункт 2</li>
<li><a href="https://google.com">Пункт 3</a></li>
<li>Пункт 4</li>
</ul>
<p id="result"></p>
const parentEl = document.getElementById('list').parentElement;
document.getElementById('result').innerHTML = 'Объект: ' + parentEl + '
' + ' Имя узла:' + ' ' + parentEl.nodeName;
3.3.6. Свойство ownerDocument
Свойство ownerDocument возвращает документ, в контексте которого узел был создан. Если нет связанного с ним документа, возвращает null. Свойство ownerDocument объекта предоставляет способ создания ссылок на другие объекты в том же документе или для доступа к свойствам и методам объекты документа, обеспечивая быстрый доступ к узлу документа без необходимости обхода иерархии узлов до самого верха. Свойство полезно при определении, к какому документу принадлежит элемент <iframe>, новое окно, вкладка или XML-документ. Используется только для чтения.
<iframe src="https://player.vimeo.com/video/159120552?byline=0&portrait=0&badge=0" width="640" height="360" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
const frame = document.querySelector('iframe');
console.log(frame.ownerDocument.location.href);
3.4. Другие свойства узлов: baseURI, isConnected и textContent
Свойство baseURI
Свойство baseURI возвращает базовый URL-адрес документа. В HTML это соответствует протоколу, доменному имени и структуре каталогов, все до последнего /. Это свойство удобно в приложениях, которые импортируют данные XML, и в этом случае источник элемента XML, вероятно, отличается от страницы HTML, на которой он обрабатывается. Используется только для чтения.
<p id="result"></p>
const pageURI = document.baseURI;
document.getElementById('result').innerHTML = 'Базовый URL страницы: ' + pageURI;
Свойство isConnected
Свойство isConnected возвращает логическое значение, указывающее, подключен ли узел (напрямую или косвенно) к объекту контекста, например объекту Document в случае обычного DOM или ShadowRoot в случае теневого DOM. Используется только для чтения.
const test = document.createElement('p');
console.log(test.isConnected); // false
document.body.appendChild(test);
console.log(test.isConnected); // true
Свойство textContent
Свойство textContent можно использовать для получения всех дочерних текстовых узлов, а также для установки содержимого узла в определенный текстовый узел. Когда он используется для получения текстового содержимого узла, он возвращает объединенную строку всех текстовых узлов, содержащихся в узле. В отличие от innerText, возвращает любой встроенный стиль или код сценария вместе с другим текстом. Когда свойство textContent используется для установки текста, содержащегося в узле, оно удалит все дочерние узлы, заменив их на новое текстовое содержимое.
<p id="result"></p>
<p id="text">Текст</p>
document.getElementById('result').textContent = 'Какой-то текст';
const text = document.getElementById('text').textContent;
console.log(text); // Текст
4. Манипуляции узлами
4.1. Создание новых узлов
4.1.1. Метод appendChild()
Метод appendChild() добавляет узел (или несколько узлов) в конец списка дочерних узлов родительского узла, на котором вызывается метод. Если дочерних узлов нет, узел добавится в качестве первого дочернего узла.
<p>Привет</p>
const elementNode = document.createElement('b');
const textNode = document.createTextNode(' мир!');
//добавим эти узлы к DOM
document.querySelector('p').appendChild(elementNode);
document.querySelector('b').appendChild(textNode);
4.1.2. Метод cloneNode()
Метод cloneNode() позволяет дублировать один узел или узел и все его дочерние узлы. Принимает один логический аргумент, указывающий, следует ли выполнять глубокое копирование. Когда аргумент равен true, клонируется узел и все его поддерево; когда false, клонируется только начальный узел. Возвращаемый клонированный узел принадлежит документу, но ему не назначен родительский узел. Таким образом, клонированный узел не существует в документе до тех пор, пока не будет добавлен с помощью appendChild(), insertBefore() или replaceChild().
При клонировании узла элемента также клонируются все его атрибуты и их значения (включая встроенные события). Все, что добавлено с помощью addEventListener() или node.onclick, не клонируется.
<ul id="menu">
<li>Главная</li>
<li>Услуги</li>
<li>О нас</li>
<li>Контакты</li>
</ul>
const menu = document.querySelector('#menu').cloneNode(true);
menu.setAttribute('id', 'menu-mobile');
document.body.appendChild(menu);
4.1.3. Метод insertBefore()
Метод insertBefore() вставляет узел перед другим узлом в качестве дочернего узла родительского узла. Принимает два параметра, указанные через запятую, — узел для вставки и узел, перед которым будет вставлен новый узел. Если у родительского узла нет дочерних узлов, то после вставки узел будет единственным дочерним узлом.
<ul id="menu">
<li>Услуги</li>
<li>О нас</li>
<li>Контакты</li>
</ul>
const menu = document.getElementById('menu');
// создаем новый узел li
const li = document.createElement('li');
li.textContent = 'Главная';
// вставляем новый узел перед первым элементом списка
menu.insertBefore(li, menu.firstElementChild);
4.1.4. Метод replaceChild()
Метод replaceChild() заменяет один узел другим. Метод принимает два аргумента: узел для вставки и узел для замены. Когда узел вставляется с помощью replaceChild(), все его указатели отношений дублируются из узла, который он заменяет. Несмотря на то, что замененный узел технически по-прежнему принадлежит тому же документу, он больше не имеет определенного местоположения в документе.
<div id="div-1">Элемент 1</div>
<div id="div-2">Элемент 2</div>
//замена узла элемента
const divFirst = document.getElementById('div-1');
var newP = document.createElement('p');
newP.textContent = 'Новый элемент 1';
divFirst.parentNode.replaceChild(newP, divFirst);
//замена текстового узла
const divSecond = document.getElementById('div-2').firstChild;
const divText = document.createTextNode('Элемент 2 новый текст');
divSecond.parentNode.replaceChild(divText, divSecond);
4.1.5. Метод removeChild()
Метод removeChild() удаляет дочерний узел из родительского узла. Удаление происходит в несколько этапов: сначала нужно выбрать узел, который хотите удалить; затем получить доступ к его родительскому элементу, как правило, с помощью свойства parentNode. После чего вызвать метод removeChild(), передавая ему ссылку на удаляемый узел.
Удалённый дочерний узел остаётся в памяти, но больше не является частью DOM. Повторно использовать удалённый узел можно с помощью ссылки на объект — oldChild.
//удаление узла элемента без указания его родительского узла
const divFirst = document.getElementById('div-1');
divFirst.parentNode.removeChild(divFirst);
//удаление текстового узла
const divSecond = document.getElementById('div-2').firstChild;
divSecond.parentNode.removeChild(divSecond);
4.2. Проверка позиции узла в дереве DOM: методы compareDocumentPosition() и contains()
Метод compareDocumentPosition()
Метод compareDocumentPosition() определяет связь между двумя узлами и возвращает битовую маску, указывающую на связь. Значения битовой маски показаны в следующей таблице. Узел может иметь более одного типа отношений с другим узлом. Например, когда узел одновременно содержит (16) и предшествует (4), возвращаемое значение из compareDocumentPosition() будет равно 20.
Числовой код | Описание |
---|---|
1 | DOCUMENT_POSITION_DISCONNECTED Означает, что два узла не принадлежат одному и тому же документу. |
2 | DOCUMENT_POSITION_PRECEDING Означает, что переданный узел предшествует выбранному узлу. |
4 | DOCUMENT_POSITION_FOLLOWING Означает, что переданный узел следует за выбранным узлом. |
8 | DOCUMENT_POSITION_CONTAINS Означает, что переданный узел является предком выбранного узла. |
16 | DOCUMENT_POSITION_CONTAINED_BY Означает, что переданный узел является потомком выбранного узла. |
32 | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC Означает, что два узла не имеют отношения друг к другу или являются двумя атрибутами одного и того же элемента. |
<p id="p1">Первый параграф</p>
<p id="p2">Второй параграф</p>
const p2Position = p1.compareDocumentPosition(p2); // p1 - узел, который сравнивается, p2 - узел, с которым идёт сравнение
console.log(p2Position); // 4, то есть p2 идет за p1
Метод contains()
Метод contains() позволяет узнать, является ли данный узел потомком другого. Метод вызывается для узла-предка, с которого должен начинаться поиск, и принимает единственный аргумент, который является предполагаемым узлом-потомком. Метод возвращает значение true, если узел является потомком данного узла, в противном случае возвращает false.
<body>
<header></header>
<main></main>
<footer></footer>
<script></script>
</body>
const footerNode = document.querySelector('footer');
const scriptNode = document.querySelector('script');
console.log(footerNode.contains(scriptNode)); // false
Метод также можно использовать, например, для проверки, содержит ли данный элемент указанный класс:
<body class="post-template-default single single-post single-format-standard"></body>
const bodyClass = document.body;
console.log(bodyClass.classList.contains('post-template-default')); // true
4.3. Определение идентичности узлов с помощью метода isEqualNode()
Метод isEqualNode() проверяет равенство двух узлов. Два узла равны, если выполняются следующие условия:
- Узлы одного типа;
- Атрибуты nodeName, localName, namespaceURI, prefix и nodeValue нулевые или имеют одинаковую длину и идентичны посимвольно;
- Атрибуты NamedNodeMaps равны нулю или имеют одинаковую длину, и для каждого узла, существующего в одной карте, есть узел, который существует в другой карте и является равным, хотя и не обязательно с тем же индексом.
- Списки узлов дочерних узлов равны, то есть они оба нулевые или имеют одинаковую длину и содержат одинаковые узлы с одним и тем же индексом. Рекомендуется нормализовать узлы перед сравнением.
<ul>
<li><a href="">Ссылка</a></li>
<li><a href="">Ссылка</a></li>
</ul>
<p>Параграф 1</p>
<p>Параграф 2</p>
const listItem = document.querySelectorAll('li');
console.log(listItem[0].isEqualNode(listItem[1])); // true
const p = document.querySelectorAll('p');
console.log(p[0].isEqualNode(p[1])); // false
4.4. Определение отношений между узлами: методы hasChildNodes() и getRootNode()
Метод hasChildNodes()
Метод hasChildNodes() возвращает true, если узел имеет один или несколько дочерних узлов, и false в противном случае. Этот способ более эффективный, чем запрос childNodes.length.
<ul id="list">
<li>Пункт 1</li>
<li>Пункт 2</li>
<li><a href="https://google.com">Пункт 3</a></li>
<li>Пункт 4</li>
</ul>
const listItems = document.getElementById("list");
if ( listItems.hasChildNodes() ) {
listItems.removeChild( listItems.firstElementChild );
}
Метод getRootNode()
Метод getRootNode() возвращает корневой узел. Вызов для элемента внутри стандартной веб-страницы вернет объект HTMLDocument, представляющий всю страницу.
Вызов для элемента внутри теневого DOM вернет связанный с ним ShadowRoot.
<div class="js-parent">
<div class="js-child"></div>
</div>
<div class="js-shadowHost"></div>
const parent = document.querySelector('.js-parent'),
child = document.querySelector('.js-child'),
shadowHost = document.querySelector('.js-shadowHost');
console.log(parent.getRootNode().nodeName); // #document
console.log(child.getRootNode().nodeName); // #document
// создадим теневое дерево
const shadowRoot = shadowHost.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = 'Содержимое теневого дерева';
const shadowChild = shadowRoot.querySelector('.js-shadowChild');
console.log(shadowChild.getRootNode() === shadowRoot); // true
console.log(shadowChild.getRootNode({ composed: false }) === shadowRoot); // true
console.log(shadowChild.getRootNode({ composed: true }).nodeName); // #document
5. Пространства имен XML: методы lookupNamespaceURI(), isDefaultNamespace() и lookupPrefix()
Пространства имен XML позволяют размещать в одном документе элементы из разных языков, основанных на XML, не опасаясь конфликтов имен элементов. Пространства имен объявляются с использованием семейства зарезервированных атрибутов. Имя такого атрибута должно быть либо xmlns, либо иметь xmlns: в качестве префикса.
Описанные ниже методы в первую очередь полезны, когда у вас есть ссылка на узел, но вы не знаете его связи с остальной частью документа.
<svg xmlns:svg="http://www.w3.org/2000/svg" height="1"></svg>
Метод lookupNamespaceURI()
Метод lookupNamespaceURI() принимает префикс в качестве параметра и возвращает пространство имен, представленное префиксом (prefix), или пространство имен по умолчанию, если аргумент prefix является пустой строкой.
Когда метод вызывается с префиксом в качестве аргумента, он должен возвращать URI пространства имен для данного префикса. Когда метод lookupNamespaceURI() вызывается с пустой строкой в качестве аргумента (представляющего пространство имен по умолчанию), он должен выполнить одно из следующих действий:
Если существует пространство имен по умолчанию, возвращает URI пространства имен по умолчанию. Если пространства имен по умолчанию нет, возвращает либо пустую строку, либо null, либо, если это разрешено привязкой языка, — undefined.
const svgElem = document.getElementsByTagName('svg')[0];
console.log(svgElem.lookupNamespaceURI("")); // http://www.w3.org/2000/svg
Метод isDefaultNamespace()
Метод isDefaultNamespace() принимает URI пространства имен в качестве аргумента. Он возвращает логическое значение, которое равно true, если пространство имен является пространством имен по умолчанию на данном узле, и false в противном случае. Пространство имен HTML-элемента по умолчанию всегда равно "". Для элемента SVG он задается атрибутом xmlns.
const svgElem = document.getElementsByTagName('svg')[0];
console.log(svgElem.isDefaultNamespace("")); // false
console.log(svgElem.isDefaultNamespace("http://www.w3.org/2000/svg")); // true
Метод lookupPrefix()
Метод lookupPrefix() возвращает строку, содержащую префикс для данного URI пространства имен, если он присутствует, и null в противном случае. Если с префиксом пространства имен связано более одного префикса, возвращаемый префикс пространства имен зависит от реализации.
const svgElem = document.getElementsByTagName('svg')[0];
console.log(svgElem.lookupPrefix("http://www.w3.org/2000/svg")); // null
6. Объединение родственных текстовых узлов в один с помощью метода normalize()
Метод normalize() используется для объединения родственных текстовых узлов в один текстовый узел. Родственные текстовые узлы обычно встречаются тогда, когда текст программно добавляется в DOM.
<div></div>
const pElem = document.createElement('p');
const text1 = document.createTextNode('Привет');
const text2 = document.createTextNode(' мир!');
pElem.appendChild(text1);
pElem.appendChild(text2);
document.querySelector('div').appendChild(pElem);
console.log(document.querySelector('p').childNodes.length); // 2
document.querySelector('div').normalize();
console.log(document.querySelector('p').childNodes.length); // 1
По материалам DOM Level 3, DOM Level 4, Node