触发事件的顺序

An order of triggered events

有一个 <div> 和两个 class。对于每个 class,都有一个点击触发事件,每个 class 都有一个单独的事件。有没有一种方法可以确保 class class_one 的事件总是首先触发,并且总是 console.log("First") 的事件首先被触发。

$('body').on('click', '.class_one', function() {
  console.log("First")
})

$('body').on('click', '.class_two', function() {
  console.log("Second")
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="class_one class_two">Click me</div>

事件不会在 classes 上触发,而是在元素上触发。如果 classes "class_one" 和 "class_two" 设置在同一个元素上,那么事件将按照它们绑定的相同顺序被调用。然而,事件会冒泡,这意味着 "click" 事件首先在元素被点击时触发,然后是其父元素,依此类推。

这意味着如果您有能力更改 DOM,您可以强制首先触发具有 class "class_one" 的元素上的事件。这可以通过从元素中删除 "class_two" class 并将其包裹在 "class_one" 元素周围来完成。

此行为可在 jQuery on 文档中找到:

When a selector is provided, the event handler is referred to as delegated. The handler is not called when the event occurs directly on the bound element, but only for descendants (inner elements) that match the selector. jQuery bubbles the event from the event target up to the element where the handler is attached (i.e., innermost to outermost element) and runs the handler for any elements along that path matching the selector.

$('body').on('click', '.class_one', function() {
  console.log("First")
})

$('body').on('click', '.class_two', function() {
  console.log("Second")
})

$('body').on('click', '.class_one', function() {
  console.log("Third")
})

$('body').on('click', '.class_two', function() {
  console.log("Fourth")
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="class_two">
  <div class="class_one">Click me</div>
</div>


就像上面已经说过的:如果 classes "class_one" 和 "class_two" 设置在同一个元素上,那么事件将按照它们绑定的相同顺序被调用。

也可以在 on 文档中找到:

Event handlers bound to an element are called in the same order that they were bound.

此 属性 可用于注册两个充当 "register" 的事件并触发添加到此 "register" 的所有事件(示例中的简单数组)。

此解决方案不需要您更改 DOM,而是需要您更改 JavaScript 中的事件注册。

const class_one_click_fns = [],
      class_two_click_fns = [];

$('body').on('click', '.class_one', function(...args) {
  class_one_click_fns.forEach(fn => fn.call(this, ...args))
})

$('body').on('click', '.class_two', function(...args) {
  class_two_click_fns.forEach(fn => fn.call(this, ...args))
})

class_one_click_fns.push(function () {
  console.log("First")
})

class_two_click_fns.push(function () {
  console.log("Second")
})

class_one_click_fns.push(function () {
  console.log("Third")
})

class_two_click_fns.push(function () {
  console.log("Fourth")
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="class_one class_two">Click me</div>