Навигация по DOM-элементам
Свойства узлов
Свойства для поика любых узлов
childNodes возвращает NodeList всех дочерних узлов, включая текстовые.
firstChild, lastChild – первый и последний дочерние узлы.
previousSibling, nextSibling – соседи-узлы.
parentNode – родитель-узел.
Свойства для поиска узлов-элементов
children возвращает HTMLCollection всех дочерних узлов-элементов.
firstElementChild, lastElementChild – первый и последний дочерние элементы.
previousElementSibling, nextElementSibling – соседи-элементы.
parentElement – родитель-элемент.
Отличие parentElement от parentNode:
document.documentElement.parentElement === null
document.documentElement.parentNode === document
Таблицы
table.rows – HTMLCollection строк <tr> таблицы.
tr.cells - HTMLCollection <td> и <th> ячеек, находящихся внутри строки <tr>.
table.tBodies – HTMLCollection элементов таблицы <tbody>.
table.caption/tHead/tFoot – ссылки на элементы таблицы <caption>, <thead>, <tfoot>.
tr.sectionRowIndex – номер строки <tr> в текущей секции <thead>/<tbody>/<tfoot>.
tr.rowIndex – номер строки <tr> в таблице (включая все строки таблицы).
td.cellIndex – номер ячейки в строке <tr>.
HTLMCollection vs NodeList
"Живая" коллекция - всегда отражает текущее состояние документа и автоматически обновляется при его изменении.
HTMLCollection - всегда "живая" коллекция и хранит только узлы-элементы.
NodeList может быть как "живой", так и статической коллекцией и хранит любые типы узлов. Есть методы forEach(), entries(), keys() и values().
childNodes и document.getElementsByName() возвращают "живую" коллекцию NodeList.
querySelectorAll() возвращает статическую коллекцию NodeList.
let elems = document.body.childNodes;
console.log(elems.constructor === NodeList); // true
console.log(elems.length); // 1
document.body.append( document.createElement('div') );
console.log(elems.length); // 2
Поиск: getElement*, querySelector*
document.getElementById - ищет элемент по идентификатору id.
document.getElementsByName - возвращает NodeList элементов с заданным атрибутом name.
elem.querySelectorAll - возвращает NodeList элементов, удовлетворяющих CSS-селектору.
elem.querySelector - возвращает первый элемент, соответствующий CSS-селектору.
elem.getElementsByClassName - возвращает HTMLCollection элементов с заданным классом.
elem.getElementsByTagName - возвращает HTMLCollection элементов с заданным тегом. Передав "*" вместо тега, возвращает всех потомков.
Другие методы
elem.matches(css) - вернет true, если elem удовлетворяет CSS-селектору, иначе false.
elem.closest(css) - возвращает ближайшего предка (включая себя), соответствующего CSS-селектору.
elemA.contains(elemB) - вернет true, если elemB потомок elemA, либо elemA === elemB, иначе false.
Атрибуты и свойства узлов
Тип, тег и содержимое
Каждый DOM-узел принадлежит соответствующему встроенному классу. Корнем иерархии является EventTarget. От него наследует Node, от которого наследуют остальные узлы.
Свойство «nodeType»
elem.nodeType === 1 для узлов-элементов.
elem.nodeType === 3 для текстовых узлов.
elem.nodeType === 8 для узлов-комментариев.
elem.nodeType === 9 для объектов документа.
Тег: nodeName и tagName
Свойство tagName есть только у элементов, наследующих от Element. Возвращает тег элемента в верхнем регистре.
Свойство nodeName определено для любых узлов Node. Для элементов равно tagName, для остальных узлов содержит строку с типом узла.
document.body.tagName // 'BODY'
document.body.firstChild.nodeName // '#text'
innerHTML: содержимое элемента
Свойство innerHTML позволяет получить HTML-содержимое элемента в виде строки.
outerHTML: HTML элемента целиком
Запись в outerHTML не изменяет элемент, а удаляет его из внешнего контекста и вставляет вместо него новый HTML-код.
HTML: <div>Привет, мир!</div>
let div = document.querySelector('div');
div.outerHTML = '<p>Новый элемент</p>';
console.log(div.outerHTML); // <div>Привет, мир!</div>
nodeValue/data: содержимое текстового узла
Свойства nodeValue и data возвращают содержимое узла, если узел не является элементом. Иначе nodeValue возвращает null, а data - undefined.
textContent: просто текст
Возвращает содержимое любого узла за вычетом всех тегов. При записи в textContent записывает HTML-теги как обычный текст.
Свойство «hidden»
Атрибут и DOM-свойство hidden работает почти так же, как style="display:none".
HTML: <div id="elem">Мигающий элемент</div>
setInterval(() => elem.hidden = !elem.hidden, 1000);
Атрибуты и свойства
HTML-атрибуты
Когда браузер парсит HTML, чтобы создать DOM-объекты для тегов, он распознаёт стандартные атрибуты и создаёт DOM-свойства для них. Этого не происходит, если атрибут нестандартный.
HTML: <body id="test" something="non-standard">
console.log(document.body.id); // test
console.log(document.body.something); // undefined
DOM-узлы имеют свойства, зависящие от класса. Поэтому стандартный атрибут для одного тега может быть нестандартным для другого.
Все атрибуты доступны с помощью следующих методов:
elem.hasAttribute(name) – проверяет наличие атрибута.
elem.getAttribute(name) – получает значение атрибута.
elem.setAttribute(name, value) – устанавливает значение атрибута.
elem.removeAttribute(name) – удаляет атрибут.
Кроме того, elem.attributes возвращает коллекцию всех атрибутов элемента. Каждый атрибут имеет свойства name и value.
for (let attr of elem.attributes) {} // все атрибуты elem по порядку
HTML-атрибуты vs DOM-свойства
DOM-свойства и методы - обычные объекты JavaScript.
Имена HTML-атрибутов регистронезависимы, а значения - всегда строки.
Синхронизация между атрибутами и свойствами
Когда стандартный атрибут изменяется, соответствующее свойство автоматически обновляется. Это работает и в обратную сторону (за некоторыми исключениями).
input.value синхронизируется только в одну сторону: атрибут → значение. Изменение атрибута value обновит свойство, но изменение свойства не повлияет на атрибут.
DOM-свойства типизированы
DOM-свойства могут отличаться от атрибутов:
Свойство input.checked (для чекбоксов) имеет логический тип.
Атрибут style – строка, но свойство style является объектом.
Свойство href всегда содержит полный URL, даже если атрибут содержит относительный URL или просто #hash.
Нестандартные атрибуты, dataset
Все атрибуты, начинающиеся с префикса data-, зарезервированы для использования программистами. Они доступны в свойстве dataset.
Атрибуты, состоящие из нескольких слов, к примеру data-order-state, становятся свойствами, записанными с помощью верблюжьей нотации: dataset.orderState.
Изменение документа
Создание элемента
document.createElement(tag) - создаёт новый элемент с заданным тегом.
document.createTextNode(text) - создаёт новый текстовый узел с заданным текстом.
Методы вставки
node.append(...nodes or strings) – добавляет узлы или строки в конец node.
node.prepend(...nodes or strings) – вставляет узлы или строки в начало node.
node.before(...nodes or strings) – вставляет узлы или строки до node.
node.after(...nodes or strings) – вставляет узлы или строки после node.
node.replaceWith(...nodes or strings) – заменяет node заданными узлами или строками.
insertAdjacentHTML
elem.insertAdjacentHTML(where, html) - вставляет html как HTML-код. where может иметь значения:
"beforebegin" – вставить html перед elem.
"afterbegin" – вставить html в начало elem.
"beforeend" – вставить html в конец elem.
"afterend" – вставить html после elem.
elem.insertAdjacentText(where, text) - вставляет text как текст.
elem.insertAdjacentElement(where, elem) - вставляет elem как элемент.
Удаление узлов
node.remove() - удаляет узел.
Все методы вставки автоматически удаляют узлы со старых мест.
Клонирование узлов: cloneNode
elem.cloneNode(truthy) - создает глубокую копию elem со всеми дочерними элементами.
elem.cloneNode(falsy) - создает поверхностную копию elem без дочерних элементов.
DocumentFragment
new DocumentFragment - создает специальный DOM-узел, который служит обёрткой для передачи списков узлов. При вставке куда-либо, он «исчезает», вместо него вставляется его содержимое.
Стили и классы
className и classList
elem.className – строковое свойство, возвращает все классы элемента через пробел. При присваивании заменяет все существующие классы на новые.
document.body.getAttribute('class'); // 'class1'
document.body.className = 'class2 class3';
document.body.getAttribute('class'); // 'class2 class3'
elem.classList – это специальный объект с методами для добавления/удаления одного класса.
elem.classList.add/remove("class") – добавить/удалить класс.
elem.classList.toggle("class") – добавить класс, если его нет, иначе удалить.
elem.classList.contains("class") – проверка наличия класса, возвращает true/false.
Кроме того, classList является перебираемым, поэтому можно перечислить все классы в цикле for..of.
Element style
Свойство style является объектом со стилями в формате camelCase. Чтение и запись в него работают так же, как изменение соответствующих свойств в атрибуте "style".
document.body.style.backgroundColor = prompt('background color?', 'green');
Сброс стилей
При присвоении пустой строки в качестве значения свойства, браузер применит встроенные стили, как если бы такого свойства не было.
document.body.style.display = "none"; // скрыть
setTimeout(() => document.body.style.display = "", 1000); // возврат к первоначальному состоянию
elem.style.cssText позволяет задать сразу несколько стилей в виде строки, осуществляя перезапись всех стилей в атрибуте 'style'. elem.setAttribute('style', '...') работает так же.
document.body.style.height = '100px';
console.log( document.body.getAttribute('style') ); // 'height: 100px;'
document.body.style.cssText = 'width: 200px; background: yellow';
console.log( document.body.getAttribute('style') ); // 'width: 200px; background: yellow;'
Вычисленные стили: getComputedStyle
getComputedStyle(element, [pseudo]) - возвращает объект, содержащий значения всех CSS-свойств элемента, полученных после применения всех стилей и вычисления их значений.
element - элемент, значения для которого нужно получить.
pseudo - указывается, если нужен стиль псевдоэлемента, например, '::before'. Пустая строка или отсутствие аргумента означают сам элемент.
getComputedStyle требует полное свойство, например, paddingLeft, borderTopWidth. При обращении к сокращённому правильный результат не гарантируется, так как стандарта для этого нет.
Размеры и прокрутка элементов
Метрики
Существует множество JavaScript-свойств, которые позволяют получить геометрические характеристики элемента: ширину, высоту и тд. В этой главе они будут называться «метрики».
offsetParent, offsetLeft/offsetTop
Свойство offsetParent содержит ближайший предок элемента, удовлетворяющий следующим условиям:
- Является CSS-позиционированным (CSS-свойство
positionравноabsolute,relative,fixedилиsticky). - Или
<td>,<th>,<table>. - Или
<body>.
Ситуации, когда offsetParent равно null:
- Для скрытых элементов (с CSS-свойством
display:noneили когда его нет в документе). - Для элементов
<body>и<html>. - Для элементов с
position:fixed.
Свойства offsetLeft/offsetTop содержат координаты x/y относительно верхнего левого угла offsetParent (0, если offsetParent === null).
offsetWidth/offsetHeight
Свойства offsetWidth/offsetHeight cодержат «внешнюю» ширину/высоту элемента, то есть его полный размер, включая рамки.
Если элемент (или любой его родитель) имеет display:none или отсутствует в документе, то все его метрики равны нулю.
clientTop/clientLeft
Свойства clientLeft/clientTop возвращают отступы внутренней части элемента от внешней.
Отступ внутренней части от внешней определяется рамками border и полосой прокрутки (в операционной системе на арабском языке или иврите полоса прокрутки расположена слева, а не справа).
clientWidth/clientHeight
Свойства clientWidth/clientHeight содержат ширину/высоту содержимого элемента вместе с внутренними отступами padding.
scrollWidth/Height
Свойства scrollWidth/scrollHeight содержат ширину/высоту содержимого элемента, включая невидимую область (скролл).
Если полосы прокрутки нет, свойства scrollWidth/scrollHeight и clientWidth/clientHeight равны.
Эти свойства можно использовать, чтобы «распахнуть» элемент на всю ширину/высоту:
elem.style.height = `${elem.scrollHeight}px`;
scrollLeft/scrollTop
Свойства scrollLeft/scrollTop содержат ширину/высоту невидимой, уже прокрученной части содержимого элемента.
Свойства scrollLeft/scrollTop можно изменять. Установка значения scrollTop на 0 или на большое значение, такое как 1e9, прокрутит элемент в самый верх/низ соответственно.
Метод scroll делает то же самое. В качестве параметра он принимает объект со свойствами left, top и behavior:
elem.scroll({
left: 0, // свойство можно не указывать, если оно равно нулю
top: 500,
behavior: 'smooth',
});
Не стоит брать width/height из CSS
- CSS-свойства
width/heightзависят от другого свойства –box-sizing. - В CSS свойства
width/heightмогут быть равныauto(например, для инлайнового элемента). - С
getComputedStyle().width/heightмогут возникать кроссбраузерные отличия. Если есть полоса прокрутки, некоторые браузеры вычитают ее ширину из CSS-ширины, а некоторые – нет.
Размеры и прокрутка окна
Ширина/высота окна
window.innerWidth/innerHeight указывают на ширину/высоту видимой части документа, включая полосу прокрутки.
document.documentElement.clientWidth/clientHeight указывают на ширину/высоту видимой части документа, доступной для содержимого.
Ширина/высота документа
Теоретически, полный размер документа можно получить как documentElement.scrollWidth/scrollHeight.
Однако, на этом элементе эти свойства могут работать иначе. Чтобы надёжно получить полную высоту документа, следует взять максимальное из этих свойств:
let scrollHeight = Math.max(
document.body.scrollHeight, document.documentElement.scrollHeight,
document.body.offsetHeight, document.documentElement.offsetHeight,
document.body.clientHeight, document.documentElement.clientHeight
);
Получение текущей прокрутки
Свойства window.scrollX/window.scrollY содержат текущую прокрутку документа.
window.pageXOffset/window.pageYOffset - устаревшие свойства для поддержки IE.
Прокрутка: scrollTo, scrollBy, scrollIntoView
Метод scrollBy(x, y) прокручивает страницу относительно её текущего положения.
Метод scrollTo(pageX, pageY)/scrollTo(options) прокручивает страницу на абсолютные координаты, заданные pageX, pageY или объектом options со свойствами left, top, behavior.
Вызов elem.scrollIntoView(top) прокручивает страницу так, чтобы elem оказался виден. Значения top:
- если
truthyилиundefined(без аргумента), совмещает верхний крайelemс верхним краем окна - если
falsy(но неundefined), совмещает нижний крайelemс нижним краем окна
elem.scrollIntoView(viewOptions) может принимать объект со свойствами:
behavior-smooth/instant/auto, анимация скроллаblock- [start]/center/end/nearest, вертикальное выравниваниеinline-start/center/end/[nearest], горизонтальное выравнивание
Координаты
Для получения координат элемента относительно документа, необходимо текущую прокрутку документа window.scrollX/window.scrollY сложить с координатами относительно окна.
Координаты относительно окна: getBoundingClientRect
Метод elem.getBoundingClientRect() возвращает объект с координатами элемента относительно окна. Свойства:
x/y – X/Y-координаты начала прямоугольника относительно окна.
width/height – ширина/высота прямоугольника.
Дополнительные («зависимые») свойства:
top/bottom – Y-координата верхней/нижней границы прямоугольника.
left/right – X-координата левой/правой границы прямоугольника.
elementFromPoint(x, y)
Вызов document.elementFromPoint(x, y) возвращает самый глубоко вложенный элемент в окне, находящийся по координатам x, y. Для координат за пределами окна метод возвращает null.