В каком порядке сработают обработчики при клике на кнопку в DOM с вложенностью div, form, button
Что проверяют
Знаете ли вы фазы распространения события и умеете ли применить их к конкретной разметке. Следом почти всегда спрашивают, что изменится с обработчиком на фазе захвата и что будет после клика: кнопка внутри формы по умолчанию её отправляет.
Как отвечать
Событие click проходит три фазы:
- захват (capture): от
windowвниз черезdocument,html,body,div,formк цели; - цель (target): обработчики на самой
button; - всплытие (bubble): обратно вверх через
form,div,body,document,window.
Обработчики через onclick или addEventListener('click', fn) срабатывают на всплытии, поэтому порядок такой: button, form, div. Обработчик с { capture: true } срабатывает на спуске. Если на каждом элементе висят оба вида, порядок будет div (захват), form (захват), button, form (всплытие), div (всплытие). На самой цели современные браузеры сначала выполняют обработчики захвата, затем обычные. Несколько обработчиков на одном элементе в одной фазе идут в порядке регистрации.
Дальше про форму. У <button> без атрибута type тип по умолчанию submit, поэтому после всех фаз клика выполняется действие по умолчанию: на форме возникает событие submit, и страница перезагружается. Отменить можно через event.preventDefault() в обработчике click или submit, либо указать type="button".
Управление распространением:
stopPropagation(): останавливает движение события дальше, но отправку формы не отменяет;stopImmediatePropagation(): вдобавок не даёт сработать остальным обработчикам на этом же элементе;preventDefault(): отменяет действие по умолчанию, распространение продолжается.
Где спотыкаются
Говорят, что с захватом «порядок просто обратный». Это верно, только если все обработчики повешены на захват. При смешанной регистрации событие проходит элементы дважды.
Забывают про submit и удивляются перезагрузке страницы, хотя в обработчике клика ничего такого не делали.
Путают stopPropagation и preventDefault, считая, что первый отменит отправку. Заодно полезно знать, что form.submit() событие submit не вызывает, а form.requestSubmit() вызывает.