Вопросы по JavaScript. Версия 2
WIP
Почему значение атрибута id
элемента HTML
должно быть уникальным?
Потому что любой HTML-элемент
с атрибутом id
становится свойством глобального объекта window
. Это, с одной стороны, приводит к загрязнению глобального пространства имен, что плохо, с другой - к возможности получать доступ к таким элементам в скрипте напрямую, т.е. без предварительного получения ссылки на элемент с помощью таких методов как querySelector
, что хорошо:
<div id="box"></div>
console.log(box === window.box) // true
Обратите внимание: получение прямого доступа к элементу с идентификатором не работает во фреймворках, абстрагирующих работу с DOM
, например, через виртуальный DOM
(React
).
В чем разница между методами preventDefault
и stopPropagation
?
Метод preventDefault
отключает стандартную обработку события браузером, а метод stopPropagation
- распространение события, т.е. запуск родительских по отношению к элементу, в котором возникло событие, обработчиков.
Например, "дефолтная" обработка события submit
элемента form
предполагает отправку данных формы и перезагрузку страницы.
<form id="formEl">
<input type="text" id="inputEl" />
<button>Отправить</button>
</form>
formEl.onsubmit = (e) => {
e.preventDefault()
alert(inputEl.value || 'hello world')
}
Событие поднимается от целевого элемента до window
через всех его предков. Элементы, через которые проходит событие (путь события), содержится в свойстве event.path
.
<div id="outerBox">
<div id="innerBox">
<button id="firstButtonEl">Сначала нажми на меня</button>
<button id="secondButtonEl">А потом на меня</button>
</div>
</div>
window.onclick = (e) => {
console.log(`Событие #${e.eventNum} достигло объекта "window"`)
}
outerBox.onclick = (e) => {
console.log(`Событие #${e.eventNum} достигло внешнего контейнера`)
}
innerBox.onclick = (e) => {
console.log(`Событие #${e.eventNum} достигло внутреннего контейнера`)
}
firstButtonEl.onclick = (e) => {
console.log('Возникло событие нажатия первой кнопки')
e.eventNum = '1'
}
secondButtonEl.onclick = (e) => {
// !
e.stopPropagation()
console.log('Возникло событие нажатия второй кнопки')
e.eventNum = '2'
}
firstButtonEl.click()
/*
Возникло событие нажатия первой кнопки
Событие #1 достигло внутреннего контейнера
Событие #1 достигло внешнего контейнера
Событие #1 достигло объекта "window"
*/
secondButtonEl.click()
// Возникло событие нажатия второй кнопки
В чем разница между методами stopPropagation
и stopImmediatePropagation
?
Метод stopPropagation
отключает только родительские обработчики события, а метод stopImmediatePropagation
- все обработчики, кроме текущего.
<div id="outerBox">
<div id="innerBox">
<button id="firstButtonEl">Сначала нажми на меня</button>
<button id="secondButtonEl">А потом на меня</button>
</div>
</div>
outerBox.onclick = (e) => {
console.log(`Событие достигло внешнего контейнера`)
}
innerBox.onclick = (e) => {
console.log(`Событие достигло внутреннего контейнера`)
}
firstButtonEl.addEventListener('click', (e) => {
e.stopPropagation()
console.log('Первый обработчик нажатия первой кнопки')
})
firstButtonEl.addEventListener('click', (e) => {
console.log('Второй обработчик нажатия первой кнопки')
})
secondButtonEl.addEventListener('click', (e) => {
// !
e.stopImmediatePropagation()
console.log('Первый обработчик нажатия второй кнопки')
})
secondButtonEl.addEventListener('click', (e) => {
console.log('Второй обработчик нажатия второй кнопки')
})
firstButtonEl.click()
/*
Первый обработчик нажатия первой кнопки
Второй обработчик нажатия первой кнопки
*/
secondButtonEl.click()
// Первый обработчик нажатия второй кнопки