为什么在父子元素绑定到后代选择器之前,父元素会触发事件?

时间:2017-11-24 16:52:37

标签: javascript jquery jquery-events

我在我的代码中绊倒了一个奇怪的错误,其中父元素上的事件似乎在事件发生之前触发,这意味着我的e.stopPropagation()没有效果。

演示:

$(document).ready(function() {

  // Binding directly to the elements
  $(".red1").on("click", function(e) {
    alert("Clicked red1");
  });
  $(".green1").on("click", function(e) {
    alert("Clicked green1");
    e.stopPropagation();
  });

  // Binding the child from a descendant selector 
  $(".red2").on("click", function(e) {
    alert("Clicked red2");
  });
  $("body").on("click", ".green2", function(e) {
    alert("Clicked green2");
    e.stopPropagation();
  });

});
.red1,
.red2 {
  display: inline-block;
  width: 200px;
  height: 200px;
  background-color: #800;
}

.green1,
.green2 {
  display: inline-block;
  width: 100px;
  height: 100px;
  background-color: #080;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="red1">
  <div class="green1"></div>
</div>

<div class="red2">
  <div class="green2"></div>
</div>

  • 点击左侧的绿色方块可按预期工作,并显示单个提醒。
  • 点击右边的绿色方块会显示父母的事件,然后是孩子的事件。

我认为这是由于对我的约束如何运作的误解,但我似乎无法理解为什么它们按此顺序发生。

任何人都可以解释为什么会这样吗?

1 个答案:

答案 0 :(得分:2)

问题是因为您使用的是委托事件处理程序。

这意味着对于要触发的事件,它必须冒泡到指定的父元素(在您的情况下为body)。当事件通过.red2时,您分配给该元素的静态处理程序将触发。然后委托事件处理程序检查以查看事件发起者是否为.green2。如果是,则执行委托事件处理程序。这就是父处理程序首先触发的原因。

为了避免这种行为,你可以避免委托事件处理程序,因为它们非常有用,并不总是可行,或者将所有事件放在父元素上,并手动检查发起者,如下所示:

$(".red2").on("click", function(e) {
  if ($(e.target).is('.green2')) {
    alert("Clicked green2");
    e.stopPropagation();
  } else {
    alert("Clicked red2");
  }
});
.red1,
.red2 {
  display: inline-block;
  width: 200px;
  height: 200px;
  background-color: #800;
}

.green1,
.green2 {
  display: inline-block;
  width: 100px;
  height: 100px;
  background-color: #080;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="red2">
  <div class="green2"></div>
</div>