17

DOM 方法支持第三个可选的addEventListener布尔参数 (useCapture) 来指示函数是否应该使用事件冒泡或事件捕获作为传播方法。在本文中很好地展示了差异(单击示例和查看代码)。

从 SO 和博客文章的其他问题中,我得出结论,事件冒泡是首选,主要是因为 IE8- 不支持它。

假设我只需要支持 IE9+,在什么情况下事件捕获比事件冒泡更必要或更受欢迎?换句话说,在什么情况下让事件先在最外面的元素上执行,然后在最里面的元素上执行会更好?我正在寻找一个简单的真实世界示例来演示事件捕获的使用...

4

1 回答 1

5

事件捕获曾经是 Internet Explorer 浏览器之外的唯一选项:

当时两个重要的浏览器的主要区别之一是它们如何处理事件。微软在冒泡阶段工作——这意味着事件首先命中目标元素,然后向上遍历整个 DOM 并命中父节点,而 Netscape 则完全相反——这意味着事件首先传递父元素,然后向下运行到目标元素 - 捕获。这在早期给开发人员带来了很多麻烦,W3C 最终指定了一种方法,既可以工作又可以自由使用。

当不支持冒泡时,事件捕获在事件委托中很有用。例如:

某些事件(例如焦点)不会冒泡,但可以被捕获。目标元素上的内联处理程序在目标元素的捕获处理程序之前触发。

Web 平台中许多新指定的事件(例如媒体事件)不会冒泡,这对于像 Ember 这样依赖事件委托的框架来说是个问题。但是,IE9 中添加的捕获 API 可以为所有事件正确调用,并且不需要规范化层。支持捕获 API 不仅可以让我们删除 jQuery 依赖项,还可以让我们正确处理这些非冒泡事件。这将允许您使用诸如在组件中播放之类的事件,而无需手动设置事件侦听器。

自定义事件和冒泡存在以下问题:

目前,Ember 依赖 jQuery 进行事件处理,这样做会带来一些成本:

jQuery silently changes inline handlers to bubble handlers.
    This changes expected invocation order
    This can cause automated tests to fail
Events triggered via jQuery.trigger trigger handlers in a different order than events triggered by a user.
    This changes expected invocation order
    This leads to difficult to reason about and debug aberrations in behavior
    This often causes automated tests to fail
Events must flow down and bubble back up through the entire DOM before being detected by the Ember application, and then must undergo an expensive delegation process that is effectively re-bubbling to find the right handler.
Handlers attached directly within components or by non-ember plugins take precedent over handlers attached by Ember, whether this was desired or not.

    This causes component handlers to have far-reaching side-effects
    This leads to difficult to reason about and debug aberrations in behavior
    This often causes automated tests to fail

媒体播放器焦点=>播放预处理/后处理事件流将是一个简单的用例。

捕获阶段的机制使其非常适合准备或防止稍后将在冒泡阶段由事件委托应用的行为。这就是我们将在这里使用它的方式——初始化排序对象以响应鼠标点击,但就在事件开始冒泡之前,其他处理程序有机会处理它。

要利用捕获,我们必须深入到金属。jQuery 的事件方法只适用于冒泡,不让我们进入捕获阶段。捕获处理程序如下所示:

    document.addEventListener("mousedown", function(event) {
      if ($(event.target).closest(".sortable_handle").length) {
         $("article.todolist, section.todolists").sortable();
         }
      }, true);

参考

于 2016-11-26T16:02:50.787 回答