浏览 3919 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-02-17
不同浏览器在这一点上存在分歧。各版本的Firefox和最新版本的Safari会调用,而Opera和老版本的Safari就不会调用。 有人认为DOM Level 2事件规范在这一点上存有歧义,但如果仔细分析,可以确定DOM 2规范的意思确实是不应在目标阶段(target phase)调用捕获事件监听器,W3C发布的测试套件(test suite)也测试了这一点,DOM 3事件规范的草案也再次明确了这一点。 然而基于种种原因,所有版本的Gecko引擎(Firefox等浏览器)和最近版本的WebKit引擎(Safari等浏览器)都会在目标阶段调用包括捕获事件监听器在内的所有监听器,并且有些人认为应该据此修改DOM规范。这种看法确实也存在一定的合理性。 具体情况可参考: https://bugzilla.mozilla.org/show_bug.cgi?id=235441 http://bugs.webkit.org/show_bug.cgi?id=9127 总之,这一问题在短期内可能不会有确定的结果。无论如何,在使用捕获处理器时应注意避免这一不确定行为的影响。 Gotchas 元素所对应的区域如果有一部分不在任何子元素内(如文本节点),严格遵循DOM规范的浏览器,就不会执行对应的捕获事件监听器。 <div id="div1"> As DOM spec, <strong>Only this area</strong> will trigger the capturing event listener for click event on the containing div element. </div> <script> var div1 = document.getElementById('div1'); div1.addEventListener('click', function () { alert('ok'); }, true); </script> 又如,如果同一个监听器,在同一个元素上注册两次,一次useCapture为true,一次为false,那么在严格遵循DOM规范的浏览器中,监听器在整个event flow中只会被调用一次;反之则会被连续调用两次,而且函数自身是无法判断到底是作为捕获事件监听器被调用,还是作为非捕获事件监听器被调用。当然,实际上是先调用捕获事件监听器再调用非捕获事件监听器的,但是如果加上target对象上的event handler(即onclick之类的事件属性),就又产生了微妙的顺序问题。Gecko的顺序是先执行handler再执行监听器,而WebKit的顺序是先执行捕获事件监听器,再执行handler,最后执行非捕获事件监听器。 Workaround 为了解决这类不确定性,可以采用一个通用的模式如下: node.addEventListener(type, listener, true); function listener(evt) { if (evt.currentTarget == evt.target) return; ... } 这样就确保了不会在target阶段执行捕获事件监听器。我们也可以判断 evt.eventPhase != evt.CAPTURING_PHASE,但是浏览器的eventPhase也可能有bug,所以最好直接判断currentTarget是否等于target。 此外,有些时候我们反而希望确保在target阶段执行(这也正是认为应该修改DOM规范的理由之一)。可以采用以下模式: node.addEventListener(type, listener1, true); node.addEventListener(type, listener2, false); function listener1(evt) { if (evt.currentTarget == evt.target) return; ... } function listener2(evt) { if (evt.currentTarget != evt.target) return; ... } 或者 node.addEventListener(type, listener, true); node.parentNode.addEventListener(type, listener, true); function listener(evt) { if (evt.currentTarget == node.parentNode && evt.target != node || evt.currentTarget == evt.target) return; ... } 在执行顺序上,前者类似Gecko的行为,后者类似WebKit的行为。 而且最好不要使用后者,因为它强制要求事件监听器引用target节点,从而构成了闭包,这降低了listener的可重用性。 总的来说,我建议应尽可能避免使用useCapture=true,因为绝大多数需求都应在target和bubbling阶段处理,特别是涉及UI的事件。如果确实有必要使用捕获事件处理器,应优先考虑符合当前DOM规范的约束,即不在target阶段执行它。这意味着,useCapture应该用于拦截符合条件的子节点事件(许多事件常常仅限于元素),而不是用于一般的事件响应。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-02-17
我感觉仅仅需要在capture过程中触发,而不需要在target过程中触发的事件是稀少的,当我在某个元素上添加事件响应时,我一般都希望能够在该元素上发生事件是响应。
|
|
返回顶楼 | |
发表时间:2008-02-19
to Lunatic Sun:
我其实更好奇你有什么特别需求一定要使用capture event listener。 |
|
返回顶楼 | |