Что делает метод preventDefault и как он влияет на поведение событий в DOM
Что проверяют
Различаете ли вы действие браузера по умолчанию и всплытие события. Это две разные вещи, и путаница между preventDefault и stopPropagation встречается настолько часто, что вопрос держат как быстрый фильтр на понимание модели событий DOM.
Как отвечать
preventDefault отменяет стандартное действие браузера для события: отправку формы, переход по ссылке, показ контекстного меню, прокрутку по колесу, выделение текста при нажатии кнопки мыши. На распространение события он не влияет вообще: обработчики выше и ниже по дереву отработают как обычно, за это отвечает stopPropagation. Факт отмены виден через event.defaultPrevented.
form.addEventListener("submit", (event) => {
event.preventDefault();
sendForm(new FormData(form));
});Важные оговорки:
- отменяемы не все события, проверяется это через
event.cancelable, и у событий, сообщающих о свершившемся факте, отмены нет; - в пассивном слушателе вызов игнорируется, а в консоль уходит предупреждение;
- для прокрутки и касаний на корневых узлах браузеры считают слушатель пассивным по умолчанию, поэтому для отмены нужен явный признак
passive: false; - в React возврат
falseиз обработчика ничего не отменяет, нужен тот же явный вызов.
Где спотыкаются
Подставляют не тот метод. Событие «улетает» к родителю, и это лечат отменой действия по умолчанию, хотя нужен stopPropagation. В обратную сторону так же: остановка всплытия на ссылке не помешает переходу по адресу.
Отменяют действие по умолчанию на ссылках безусловно. Обработчик срабатывает и на клик средней кнопкой, и на клик с зажатым модификатором, из-за чего перестаёт работать открытие в новой вкладке, а вместе с ним и привычное поведение навигации.
Пишут отмену в обработчике касания или прокрутки и удивляются, что страница всё равно скроллится. Слушатель зарегистрирован как пассивный, вызов проигнорирован, и лечится это регистрацией с явным отключением пассивного режима, а не переносом кода в другое место.