Как работает несколько addEventListener в JavaScript?

в документе есть 2 скрипта

javascript prettyprint-override">// my_script.js goes first
document.onclick = function() {
    alert("document clicked");
};

// other_script.js comes after
// this overrides the onclick of my script,
// and alert will NOT be fired
document.onclick = function() {
    return false;
};

чтобы убедиться, что мое событие click не переопределяется другим скриптом, я переключился на addEventListener.

// my_script.js goes first
document.addEventListener("click", function() {
    alert("document clicked");
}, false);

// other_script.js comes after
document.addEventListener("click", function() {
    return false;
}, false);

теперь у меня есть еще один вопрос. С return false во втором коде определяется после alert, Почему это не предотвращает предупреждение от вызова?

Что делать, если я хочу, чтобы мой скрипт получал полный контроль над событием click (например, возвращать false все время, игнорируя события, определенные в других скрипты)?

1 ответов


что делать, если я хочу, чтобы мой скрипт получал полный контроль над событием click (например, возвращать false все время, игнорируя события, определенные в других сценариях)?

если вы можете сначала зарегистрировать свой обработчик, прежде чем они это сделают, вы можете сделать это, при условии, что браузер, который вы используете, правильно реализует события DOM3 (что он, вероятно, делает, если это не IE8 или ранее).

есть (по крайней мере) четыре вещи, связанные здесь:

  1. предупреждение по умолчанию.

  2. остановка распространения на элементы предков.

  3. остановка других обработчиков на то же самое элемент от вызова.

  4. порядок, в котором обработчики вызываются.

по порядку:

1. Предотвращение значения по умолчанию

это return false от обработчика DOM0 делает. (Подробности:история о возвращении False.) Эквивалент в DOM2 и DOM3 -preventDefault:

document.addEventListener("click", function(e) {
    e.preventDefault();
}, false);

предотвращение по умолчанию не может быть все, что имеет отношение к тому, что вы делаете, но так как вы использовали return false в вашем обработчике DOM0, и это предотвращает значение по умолчанию, я включаю его здесь для полноты.

2. Остановка распространения на элементы предков

обработчики DOM0 не могут этого сделать. Дом2 те сделай, ВИА stopPropagation:

document.addEventListener("click", function(e) {
    e.stopPropagation();
}, false);

но stopPropagation не останавливает другие обработчики на том же элементе, вызываемом. От спец:

на stopPropagation используется метод предотвращения дальнейшего распространения события во время потока событий. Если этот метод вызывается любым EventListener событие перестанет распространяться по дереву. событие завершит отправку всем слушателям по текущему EventTarget перед потоком событий останавливает.

(Курсив мой.)

3. Остановка других обработчиков на то же самое элемент с именем

естественно, это не подошло для DOM0, потому что не могло быть другие обработчики для того же события на том же элементе. :-)

насколько мне известно, в DOM2 это невозможно сделать, но DOM3 дает нам stopImmediatePropagation:

document.addEventListener("click", function(e) {
    e.stopImmediatePropagation();
}, false);

некоторые библиотеки предлагают эту функцию (даже в системах без DOM3, таких как IE8) для обработчиков, подключенных через библиотеку, см. ниже.

4. Порядок, в котором обработчики называются

опять же, не то, что связано с DOM0, потому что не могло быть других обработчиков.

в DOM2, спецификация явно говорит, что порядок, в котором вызываются обработчики, прикрепленные к элементу, не гарантируется; но DOM3 изменяет это, говоря, что обработчики назвал в том порядке, в котором они зарегистрированы.

во-первых, от DOM2 1.2.1:

хотя все EventListeners на EventTarget гарантированы, что будут вызваны любым событием которое получено этим EventTarget, нет спецификации относительно порядка, в котором они получат событие в отношении другого EventListeners на EventTarget.

но это заменено DOM3 3.1:

далее реализация должна определить прослушиватели событий-кандидатов текущей цели. Это должен быть список всех прослушивателей событий, зарегистрированных в текущей цели в порядке их регистрации.

(Курсив мой.)

некоторые библиотеки гарантируют порядок, при условии, что вы подключаете события с библиотекой.

также стоит отметить, что в Предшественник Microsoft на DOM2 (например, attachEvent), это было противоположно приказу DOM3: обработчики были вызваны реверс порядок регистрации.


Итак, взяв #3 и #4 вместе, если вы можете сначала зарегистрировать свой обработчик, он будет вызван первым, и вы можете использовать stopImmediatePropagation для предотвращения вызова других обработчиков. При условии, что браузер правильно реализует DOM3.


все это (включая тот факт, что IE8 и ранее не даже реализовать события DOM2, а тем более DOM3) - одна из причин, по которой люди используют библиотеки, такие как jQuery, некоторые из которых гарантируют порядок (пока все подключает свои обработчики через рассматриваемую библиотеку) и предлагают способы остановить даже другие обработчики на том же элементе, вызываемом. (С jQuery, например, порядок есть порядок, в котором они были прикреплены, и вы можете использовать stopImmediatePropagation для остановки вызовов других обработчиков. Но я не пытаюсь продать jQuery здесь, просто объясняя, что некоторые libs предложите больше функциональности чем основной материал DOM.)