2011-11-18 122 views
7

正如您所知道的,事件通常会以javascript的形式冒泡,因此首先执行触发事件的元素的事件处理程序,然后再调用父元素的事件处理程序,等等。这种行为会导致我目前正在处理的项目出现一些问题,我宁愿将执行顺序颠倒过来。在javascript中冒泡的逆向事件

我figuered指出,使用超时解决方案:

$(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元素的事件处理程序在等待1ms之后执行,等等。所以事件的执行顺序是相反的。

我第一次测试的结果是肯定的,但我仍然不确定这个解决方案是否存在问题或缺点。你对这个解决方案有什么看法?关于如何解决这个问题的其他想法也非常感谢。

+1

我不明白你为什么把父母*的数量设置为*以毫秒为单位的时间*。 – pimvdb

+2

他这样做是为了确保叶元素上的执行事件处理程序将被延迟太多,以至于它将在链中最后执行。 – WTK

回答

14

反向事件冒泡称为捕获阶段。

DOM event architecture

true作为第三个参数来Event.addEventListener有它触发捕获阶段

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

当然它不会在传统平台上的工作。您需要一个DOM3事件填充来模拟事件系统。随意贡献DOM-shim

+0

是的,当然,除了它没有在每个浏览器中实现。看到这里http://www.quirksmode.org/js/events_order。html – WTK

+1

@WTK谁在乎传统平台? – Raynos

+3

@Raynos客户^^ –

0

我可以看到你的解决方案的一个巨大缺点是,对于每个处理过的事件,你必须向上遍历DOM,从this开始建立父母数量。

在每个事件处理程序中以这种方式遍历=低性能。

+0

每次事件触发时,它都会从文档根部一直运行到触发事件的元素,然后一直运行到根。在你的处理程序代码中增加一个额外的文件根目录不会花费太多时间。 –

0

您可以尝试模拟它,但可能会造成很多麻烦。

这里是非常非常简单的例子(和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

感谢您的回答。我需要这个反向事件处理程序执行的原因相当复杂,总之很难解释。基本上,我有一个任意html文档的不同元素的mouseover处理程序。通常,首先执行外部元素的事件处理程序,因为在到达内部元素之前,将鼠标指针移到外部元素上。但是,对于包含内部元素而没有任何填充的元素,这会失败,因为您不必移动到外部元素以达到内部元素。所以我想颠倒顺序以保持一致的行为 – Simon

+0

嗯......你总是可以使用某种'继承',就像这里:http://jsfiddle.net/GEFAq/ 2 /它应该工作(触发是同步的,据我所知)。这是基本概念 - 在执行任何其他操作之前,元素处理程序停止传播并在父元素上触发相同的事件。 –

+0

但是,如果你真的不在乎旧的浏览器,比不打扰,并与@Raynos解决方案:) –