当与后代选择器绑定时,为什么事件会在其子元素之前在父元素上触发?
Why does an event fire on a parent element before it's child when bound with a descendent selector?
我被代码中的一个奇怪错误绊倒了,父元素上的事件似乎在其子元素上的事件之前触发,这意味着我的 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>
- 单击左侧的绿色方块会按预期工作并显示一个警报。
- 点击右侧的绿色方块似乎会触发父事件,然后是子事件。
我认为这是由于我误解了绑定的工作方式,但我似乎无法理解为什么它们会按此顺序出现。
谁能解释为什么会这样?
问题是因为您使用的是委托事件处理程序。
这意味着要触发事件,它必须冒泡到指定的父元素(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>
我被代码中的一个奇怪错误绊倒了,父元素上的事件似乎在其子元素上的事件之前触发,这意味着我的 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>
- 单击左侧的绿色方块会按预期工作并显示一个警报。
- 点击右侧的绿色方块似乎会触发父事件,然后是子事件。
我认为这是由于我误解了绑定的工作方式,但我似乎无法理解为什么它们会按此顺序出现。
谁能解释为什么会这样?
问题是因为您使用的是委托事件处理程序。
这意味着要触发事件,它必须冒泡到指定的父元素(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>