Что такое DOM
DOM или Document Object Model (объектная модель документа) — это прикладной программный интерфейс (API) для работы с HTML и XML документами. Когда браузер первый раз читает («парсит») HTML документ, он формирует большой объект, действительно большой объект, основанный на документе — DOM. DOM представляет собой древовидную структуру (дерево документа). DOM используется для взаимодействия и изменения самой структуры DOM или его отдельных элементов и узлов.
В JS DOM представлен объектом Document. Объект Document имеет большое количество методов для работы с элементами, их созданием, модификацией, удалением и т.д.
Что такое распространение события (Event Propagation)?
Когда какое-либо событие происходит в элементе DOM, оно на самом деле происходит не только в нем. Событие «распространяется» от объекта Window до вызвавшего его элемента (event.target). При этом событие последовательно пронизывает (затрагивает) всех предков целевого элемента. Распространение события имеет три стадии или фазы:
Фаза погружения (захвата, перехвата) — событие возникает в объекте Window и опускается до цели события через всех ее предков.
Целевая фаза — это когда событие достигает целевого элемента.
Фаза всплытия — событие поднимается от event.target, последовательно проходит через всех его предков и достигает объекта Window.
Что такое всплытие события?
Когда событие происходит в элементе DOM, оно затрагивает не только этот элемент. Событие «всплывает» (подобно пузырьку воздуха в воде), переходит от элемента, вызвавшего событие (event.target), к его родителю, затем поднимается еще выше, к родителю родителя элемента, пока не достигает объекта Window.
Допустим, у нас есть такая разметка:
<div>
<div>
<div>1</div>
</div>
</div>
Объяснить код с
И такой JS:
function addEvent(el, event, callback, isCapture = false) {
if (!el || !event || !callback || typeof callback !== ‘function’) return
if (typeof el === 'string') {
el = document.querySelector(el)
}
el.addEventListener(event, callback, isCapture) }addEvent(document, ‘DOMContentLoaded’, () => {
const child = document.querySelector(‘.child’)
const parent = document.querySelector(‘.parent’)
const grandparent = document.querySelector(‘.grandparent’)
addEvent(child, 'click', function(e) {
console.log('child')
})
addEvent(parent, 'click', function(e) {
console.log('parent')
})
addEvent(grandparent, 'click', function(e) {
console.log('grandparent')
})
addEvent('html', 'click', function(e) {
console.log('html')
})
addEvent(document, 'click', function(e) {
console.log('document')
})
addEvent(window, 'click', function(e) {
console.log('window')
}) })У метода addEventListener есть третий необязательный параметр — useCapture. Когда его значение равняется false (по умолчанию), событие начинается с фазы всплытия. Когда его значение равняется true, событие начинается с фазы погружения (для «прослушивателей» событий, прикрепленных к цели события, событие находится в целевой фазе, а не в фазах погружения или всплытия. События в целевой фазе инициируют все прослушиватели на элементе в том порядке, в котором они были зарегистрированы независимо от параметра useCapture — прим. пер.). Если мы кликнем по элементу child, в консоль будет выведено: child, parent, grandparent, html, document, window. Вот что такое всплытие события.
Что такое погружение события?
Когда событие происходит в элементе DOM, оно происходит не только в нем. В фазе погружения событие опускается от объекта Window до цели события через всех его предков.
Разметка:
<div>
<div>
<div>1</div>
</div>
</div>
Объяснить код с
JS:
function addEvent(el, event, callback, isCapture = false) {
if (!el || !event || !callback || typeof callback !== ‘function’) return
if (typeof el === 'string') {
el = document.querySelector(el);
}
el.addEventListener(event, callback, isCapture) }addEvent(document, ‘DOMContentLoaded’, () => {
const child = document.querySelector(‘.child’)
const parent = document.querySelector(‘.parent’)
const grandparent = document.querySelector(‘.grandparent’)
addEvent(child, 'click', function(e) {
console.log('child');
}, true)
addEvent(parent, 'click', function(e) {
console.log('parent')
}, true)
addEvent(grandparent, 'click', function(e) {
console.log('grandparent')
}, true)
addEvent('html', 'click', function(e) {
console.log('html')
}, true)
addEvent(document, 'click', function(e) {
console.log('document')
}, true)
addEvent(window, 'click', function(e) {
console.log('window')
}, true) }) Объяснить код сУ метода addEventListener есть третий необязательный параметр — useCapture. Когда его значение равняется false (по умолчанию), событие начинается с фазы всплытия. Когда его значение равняется true, событие начинается с фазы погружения. Если мы кликнем по элементу child, то увидим в консоли следующее: window, document, html, grandparent, parent, child. Это и есть погружение события.
В чем разница между методами event.preventDefault() и event.stopPropagation()?
Метод event.preventDefault() отключает поведение элемента по умолчанию. Если использовать этот метод в элементе form, то он предотвратит отправку формы (submit). Если использовать его в contextmenu, то контекстное меню будет отключено (данный метод часто используется в keydown для переопределения клавиатуры, например, при создании музыкального/видео плеера или текстового редактора — прим. пер.). Метод event.stopPropagation() отключает распространение события (его всплытие или погружение).
Как узнать об использовании метода event.preventDefault()?
Для этого мы можем использовать свойство event.defaulPrevented, возвращающее логическое значение, служащее индикатором применения к элементу метода event.preventDefault.
Почему obj.someprop.x приводит к ошибке?
const obj = {}
console.log(obj.someprop.x)
Ответ очевиден: мы пытается получить доступ к свойству x свойства someprop, которое имеет значение undefined. obj.__proto__.__proto = null, поэтому возвращается undefined, а у undefined нет свойства x.
Что такое цель события или целевой элемент (event.target)?
Простыми словами, event.target — это элемент, в котором происходит событие, или элемент, вызвавший событие.
Имеем такую разметку:
<div>
<div>
<div>
<button>
Button
</button>
</div>
</div>
</div>
И такой простенький JS:
function clickFunc(event) {
console.log(event.target)
}
Мы прикрепили «слушатель» к внешнему div. Однако если мы нажмем на кнопку, то получим в консоли разметку этой кнопки. Это позволяет сделать вывод, что элементом, вызвавшим событие, является именно кнопка, а не внешний или внутренние div.
Event.currentTarget — это элемент, к которому прикреплен прослушиватель событий.
Аналогичная разметка:
<div>
<div>
<div>
<button>
Button
</button>
</div>
</div>
</div>
И немного видоизмененный JS:
function clickFunc(event) {
console.log(event.currentTarget)
}
Мы прикрепили слушатель к внешнему div. Куда бы мы ни кликнули, будь то кнопка или один из внутренних div, в консоли мы всегда получим разметку внешнего div. Это позволяет заключить, что event.currentTarget — это элемент, к которому прикреплен прослушиватель событий.