Введение в DOM.
DOM (Document Object Model) - внутренние объекты и функции браузера, хранящие состояние страницы.JS через это API имеет полный доступ ко всему тому, что есть в HTML и CSS.
Корень
Корнем дерева элементов DOM является объект document
Поиск элементов
Что бы найти элемент, нужно обратится к методу document, или любого другого элемента, в котором нужно что-то найти:
1var el = document.getElementById("someId"); //обратите внимания, без #2//в последних браузерах все `id` автоматически попадают в глобальную область видимости (в объект window)3var el2 = document.querySelector("#someId"); //поиск по любому селектору, аналог jQuery4var el3 = document.querySelectorAll("a"); //поиск всех тегов a
Создание элементов DOM
1document.createElement("a"); //обратите внимание, без <>
Добавление элементов:
1var tr = document.createElement("tr");2var td = document.createElement("td");3var td2 = document.createElement("td");45tr.appendChild(td); //добавление ячейки в конец строки таблицы.6tr.insertBefore(td2, tr.childNodes[0]); //добавление ячейки перед первой ячейкой (в самое начало строки таблицы)
Ссылка на родительский элемент находится в свойстве parentElement:
1tr.childNodes[0].parentElement === tr
Свойства объектов или наборов объектов элементов в DOM
value- свойство а не функция для значения поля ввода.attributes- объектattributesс атрибутами html-тега. Также есть 4 функции для работы с атрибутами:hasAttribute- проверка на наличие атрибутаgetAttribute- чтениеsetAttribute- записьremoveAttribute- удалениеstyle- объект стиля элементаinnerHTML- строка вложенного HTML в элементе.innerText- строка вложенного текста в элементе.
Нюансы
Элемент в дереве
может встречаться только один раз. Вы не можете вставить элемент дважды в дерево. Если вы хотите создать копию элемента в вашем DOM-дереве, используйте cloneNode.
HTML/CSS
Всё, что вы видели в HTML/CSS может быть установлено как свойства объекта-узла DOM и тут же будет отображено в браузере
children и childNodes
- Узлами (
Node) может быть любой текст в HTML, в том числе обычный текст и тот или иной тэг. Дочерние элементы каждого элемента находятся в псевдомассивеchildNodes - В псевдомассиве
childrenнаходятся только дочерние узлы-теги, но без обычного текста.

HTMLCollection это список узлов. Отдельный узел может быть доступен по порядковому номеру или имени узла и атрибута. Коллекции в HTML DOM являются живыми. Коллекции обновляются при изменении документа. Коллекция HTML всегда находится в DOM, в то время как NodeList является более универсальной конструкцией, которая может или не может быть в DOM.
NodeList является коллекцией узлов. NodeList обеспечивает уровень абстракции над коллекцией узлов, не определяя и не ограничивая как это коллекция используется. Объекты NodeList являются “живыми” или статическим, в зависимости от способа используемого для их получения.
События
Каждый элемент DOM содержит множество свойств on..., в которые вы можете занести тот или иной обработчик события:
1document.onmousemove = function(){2 document.write("mouse move <br/>");3}
Так же можно добавлять обработчики используя метод элемента addEventListener:
1document.addEventListener("mousemove",function(){2 document.write("mouse move <br/>");3});
Как было уже отмечено, DOM - это дерево из элементов верстки страницы, каждый из которых представлен объектом Javascript. Кроме данных, в объектах бывают те или иные действия, которые объект может осуществлять - методы.
Установка обработчиков
Для обработки событий вы можете назначить функцию-обработчик события путем присвоения ключа объекта:
1var element = document.getElementById('root')2element.onmousemove = function(event){3 console.log(this, event);4}
Так же вы можете добавить несколько обработчиков на одно и тоже событие в одном и том же элементе, используя метод addEventListener:
1var element = document.getElementById('root')23function eventHandler(event){4 console.log(this, event);5}678element.addEventListener("mousemove",eventHandler);9element.addEventListener("click",eventHandler);
Данные, передаваемые в обработчик
В обработчик события передается два аргумента:
this, который ссылается на элемент, на который "навешен" обработчик. Используяthisвы можете узнать любую информацию о элементе и навешивать один и тот же обработчик на несколько элементов, если вам нужно схожее поведение на многих элементах.event, объект-событие, переданный первым аргументом в функцию-обработчик (вы можете назвать его как угодно). С помощью этого объекта можно узнать информацию о событии (нажатые кнопки мыши и клавиатуры, положение курсора мыши, и т. п.), а так же управлять обработкой потока событий:event.stopPropagation()останавливает всплытие событий (например,clickвсплывает от вложенных элементов к обрамляющим). Обрамляющие элементы не узнают о событии.event.stopImmediatePropagation()аналогичен предыдущему, однако не будут запущены даже следующие обработчики на этом элементеevent.preventDefault()запрещает браузеру запускать обработчики по умолчанию (отправку данных дляsubmitформы, переход по клику на ссылку<a>и т. п.)
addEventListener
Первый аргумент метода addEventListener - это тип события ( строка ), например: "mouseover" "mouseout" "input" "change" ... Второй аргумент - ссылка на функцию ( обработчика события ) Третий аргумент - логическое значение - будучи установленным в true, позволяет перехватить событие на фазу погружения ( capturing )
1var element = document.getElementById('root')23function eventHandler(event){4 console.log(this, event);5}
removeEventListener
Прослушивателей событий нужно удалять, поскольку они не убираются автоматически при удалении элемента
При удалении нужно передавать точно такие же аргументы, какие были переданы методу addEventListener при создании прослушивателя
🚫 Не правильно
1document.getElementById ( 'sample' )2 .addEventListener ( 'click', function ( event ) {3 console.log ( 'sample click event: ', event )4 })5document.getElementById ( 'sample' )6 .removeEventListener ( 'click', function ( event ) {7 console.log ( 'sample click event: ', event )8 })
✅ Правильно
1var elem = document.getElementById ( 'element' )2function clickHandler ( event ) {3 this.innerHTML = '<small>My content was changed!</small>'4}5elem.addEventListener ( 'click', clickHandler )6elem.removeEventListener ( 'click', clickHandler )
Всплытие событий
1<div onclick="alert('Hello!')">2 <em>Если вы кликните на <code>EM</code>, сработает обработчик на <code>DIV</code></em>3</div>
Всплытие
Принцип всплытия очень простой. Когда на элементе происходит событие, обработчики сначала срабатывают на нём, потом на его родителе, затем выше и так далее, вверх по цепочке предков.
Например, есть 3 вложенных элемента FORM > DIV > P с обработчиком на каждом
1<form onclick="alert('form')">FORM2 <div onclick="alert('div')">DIV3 <p onclick="alert('p')">P</p>4 </div>5</form>
Клик по внутреннему <p> вызовет обработчик onclick:
- Сначала на самом
<p>. - Потом на внешнем
<div>. - Затем на внешнем
<form>. И так далее вверх по цепочке до самогоdocument.

Поэтому если кликнуть на <p>, то мы увидим три оповещения: p → div → form.
Этот процесс называется «всплытием», потому что события «всплывают» от внутреннего элемента вверх через родителей подобно тому, как всплывает пузырёк воздуха в воде.
event.target
Всегда можно узнать, на каком конкретно элементе произошло событие.
Самый глубокий элемент, который вызывает событие, называется целевым элементом, и он доступен через event.target.
Отличия от this = evet.currentTarget
event.target – это «целевой» элемент, на котором произошло событие, в процессе всплытия он неизменен.
this – это «текущий» элемент, до которого дошло всплытие, на нём сейчас выполняется обработчик.
Например, если стоит только один обработчик form.onclick, то он «поймает» все клики внутри формы.
Где бы ни был клик внутри – он всплывёт до элемента <form>, на котором сработает обработчик.
При этом внутри обработчика form.onclick:
this = event.currentTargetвсегда будет элемент<form>, так как обработчик сработал на ней.event.targetбудет содержать ссылку на конкретный элемент внутри формы, на котором произошёл клик.
Прекращение всплытия
Всплытие идёт с «целевого» элемента прямо наверх. По умолчанию событие будет всплывать до элемента <html>, а затем до объекта document, а иногда даже до window, вызывая все обработчики на своём пути.
Но любой промежуточный обработчик может решить, что событие полностью обработано, и остановить всплытие.
Для этого нужно вызвать метод event.stopPropagation().
Погружение
Существует ещё одна фаза из жизненного цикла события – «погружение» (иногда её называют «перехват»). Она очень редко используется в реальном коде, однако тоже может быть полезной.
Стандарт DOM Events описывает 3 фазы прохода события:
- Фаза погружения (capturing phase) – событие сначала идёт сверху вниз.
- Фаза цели (target phase) – событие достигло целевого(исходного) элемента.
- Фаза всплытия (bubbling stage) – событие начинает всплывать.
Изображение ниже из спецификации демонстрирует, как это работает при клике по ячейке <td>, расположенной внутри таблицы:
При клике на <td> событие путешествует по цепочке родителей сначала вниз к элементу (погружается), затем оно достигает целевой элемент (фаза цели), а потом идёт наверх (всплытие), вызывая по пути обработчики.
Ранее мы говорили только о всплытии, потому что другие стадии, как правило, не используются и проходят незаметно для нас.
Обработчики, добавленные через on<event>-свойство или через HTML-атрибуты, или через addEventListener(event, handler)с двумя аргументами, ничего не знают о фазе погружения, а работают только на 2-ой и 3-ей фазах.
Чтобы поймать событие на стадии погружения, нужно использовать третий аргумент capture вот так:
1var elem = document.getElementById('root');2function handler(){}3elem.addEventListener(handler, {capture: true})4// или просто "true", как сокращение для {capture: true}5elem.addEventListener(handler, true)
Существуют два варианта значений опции capture:
- Если аргумент
false(по умолчанию), то событие будет поймано при всплытии. - Если аргумент
true, то событие будет перехвачено при погружении.
Обратите внимание, что хоть и формально существует 3 фазы, 2-ую фазу («фазу цели»: событие достигло элемента) нельзя обработать отдельно, при её достижении вызываются все обработчики: и на всплытие, и на погружение.
Давайте посмотрим и всплытие и погружение в действии:
Пример 2
Здесь обработчики навешиваются на каждый элемент внутри элемента с id ex2, чтобы увидеть в каком порядке они вызываются по мере прохода события.
Если вы кликните по <p>, то последовательность следующая:
FORM → DIV → p (фаза погружения, первый обработчик)
P (фаза цели, срабатывают обработчики, установленные и на погружение и на всплытие, так что выведется два раза)
P→ DIV → FORM (фаза всплытия, второй обработчик)
Существует свойство event.eventPhase, содержащее номер фазы, на которой событие было поймано. Но оно используется редко, мы обычно и так знаем об этом в обработчике.
Важно
Чтобы убрать обработчик removeEventListener, нужна та же фаза
Если мы добавили обработчик вот так addEventListener(..., true), то мы должны передать то же значение аргумента capture в removeEventListener(..., true), когда снимаем обработчик.