Обратное всплывающее событие в JavaScript - PullRequest
10 голосов
/ 18 ноября 2011

Как вы знаете, события обычно всплывают в javascript, поэтому сначала выполняется обработчик события элемента, который инициирует событие, затем вызывается обработчик события родительского элемента и так далее. Такое поведение вызывает некоторые проблемы в проекте, над которым я сейчас работаю, я бы предпочел поменять порядок выполнения.

Я нашел решение, которое использует таймауты:

$(element).mouseover(function(){
    var that = this;
    setTimeout(function() {
       //actual event handler, but references to "this" are replaced with "that"
    },$(this).parents().length)
 });

Таким образом, в основном обработчики событий выполняются после короткого времени ожидания, время ожидания зависит от глубины элемента в DOM-дереве: Обработчик события html-элемента выполняется сразу, обработчик события элемента body выполняется после ожидания 1 мс и так далее. Таким образом, порядок выполнения событий меняется на противоположный.

Результаты моих первых тестов положительные, но я все еще не уверен, есть ли какие-либо проблемы или недостатки с этим решением. Что вы думаете об этом решении? Другие идеи о том, как решить эту проблему, также высоко ценятся.

Ответы [ 3 ]

19 голосов
/ 18 ноября 2011

Обратное всплытие событий называется фазой захвата.

См. Архитектура событий DOM

Передача true в качестве 3-го аргумента для Event.addEventListener, чтобы он срабатывал на фазе захвата

el.addEventListener("click", function () {
  console.log("i run in capture");
}, true);

Конечно, это не будет работать на устаревших платформах.Вам понадобится прокладка событий DOM3 для эмуляции системы событий.Не стесняйтесь вносить свой вклад в DOM-шим

0 голосов
/ 18 ноября 2011

Вы можете попытаться подражать этому, но, вероятно, это может создать много проблем.

Вот очень простой пример (и для jsfiddle ).Идея состоит в том, чтобы агрегировать обратные вызовы от каждого события и вызывать их в обратном порядке в обработчике событий document (мы также очищаем наш список, чтобы обеспечить новую очередь при следующем щелчке).

<div id="a">
    <div id="b">
        <a href="/test">Click Me!</a>
    </div>
</div>
var cb = [];

$(document).click(function(evt){

    cb.unshift(function(){
        console.log('document');
    });
    var i;
    for(i=0; i<cb.length; ++i){
        cb[i].call(null, evt);
    }
    cb = [];
});

$("#a").click(function(){
    cb.unshift(function(){
        console.log('div#a');
    });
});

$("#b").click(function(){
    cb.unshift(function(){
        console.log('div#b');
    });
});

$('a').click(function(evt){
    cb.unshift(function(evt){
        evt.preventDefault();
        console.log('a');
    });
});

Может быть, вам нужно изменить свой дизайн?Не могли бы вы опубликовать больше информации, зачем вам нужно захват событий?

0 голосов
/ 18 ноября 2011

Я вижу один огромный недостаток вашего решения в том, что для каждого обработанного события вы должны обходить DOM вверх, начиная с this, чтобы установить количество родителей.

Обход таким образом в каждом событииобработчик = низкая производительность.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...