为什么$('.myClass').on("input propertychange",function(){})总是在$(document).on("input propertychange",".myClass",function(){))之前调用?

mar*_*zzz 2 jquery events

这是一个有效的例子:

$(document).on("input propertychange", ".myClass", function () {
    $('#result').append("first<br />");
});

$('.myClass').on("input propertychange", function () {
  $('#result').append("second<br />");
});
Run Code Online (Sandbox Code Playgroud)

即使我在first之前定义代码块second,它总是second先打印.

为什么?我怎样才能保证它们会以级联方式执行?

T.J*_*der 6

因为这是事件处理的工作方式.事件首先经历从窗口到文档到目标元素的捕获阶段,然后从目标元素冒泡到窗口.

你的第一个on调用附加一个click处理程序document,当被调用时,将检查事件是否通过.myClass最终目标之间匹配的任何元素document,如果是,则调用你的处理程序.您的第二个on调用将处理程序直接附加到匹配元素.在这两种情况下,你都在挂钩冒泡阶段(jQuery不支持挂钩捕获阶段).因此,在文档上匹配的委托处理程序之前调用元素本身的处理程序.(从技术上讲,当事件位于目标元素时,它处于目标阶段,而不是捕获或冒泡.但是捕获和冒泡处理程序都会在目标元素上按顺序进行处理.)

这是旧DOM3事件规范的一个很好的一体化图表:

在此输入图像描述

您可以在当前的DOM4规范中找到详细信息.

虽然jQuery不支持捕获阶段,但是addEventListener在兼容的浏览器上(因此,不是IE8和更早版本,没有捕获或addEventListener).第三个参数addEventListener让你决定是否需要capture(true)或bubbling(false); 它默认为false(在真正的现代系统中,第三个参数可以是具有各种标志的对象).

这是一个显示所有阶段中的事件的示例:

// See: https://www.w3.org/TR/domcore/#dom-event-none
const eventPhases = ["NONE", "CAPTURING_PHASE", "AT_TARGET", "BUBBLING_PHASE"];

function captureHandler(e) {
  console.log("captureHandler: " + eventPhases[e.eventPhase] + " on " + this.id);
}
function bubbleHandler(e) {
  console.log("bubbleHandler:  " + eventPhases[e.eventPhase] + " on " + this.id);
}

function hookBoth(element) {
  element.addEventListener("click", captureHandler, true);
  element.addEventListener("click", bubbleHandler, false);
}

hookBoth(document.getElementById("outer"));
hookBoth(document.getElementById("middle"));
hookBoth(document.getElementById("target"));
Run Code Online (Sandbox Code Playgroud)
<div id="outer">
  <div id="middle">
    <div id="target">Click Me</div>
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)