英文:
e.stopPropagation() on click event
问题
请告诉我为什么 e.stopPropagation()
函数不起作用?
$(document).ready(function() {
var el = '<div class="el" onclick="alert(1);"><div class="stop">X</div>Click</div>';
$("body").append(el);
})
$(document).on("click", ".stop", function(e) {
e.stopPropagation();
e.preventDefault();
alert(2);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
</body>
英文:
Please tell me why the e.stopPropagation()
function does not work?
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
$(document).ready(function() {
var el = '<div class="el" onclick="alert(1);"><div class="stop">X</div>Click</div>';
$("body").append(el);
})
$(document).on("click", ".stop", function(e) {
e.stopPropagation();
e.preventDefault();
alert(2);
});
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
</body>
<!-- end snippet -->
答案1
得分: 4
> 为什么 e.stopPropagation()
函数不起作用?
它确实起作用。观察:
$(document).on("click", ".outer", function(e) {
alert(3);
});
$(document).on("click", ".el", function(e) {
e.stopPropagation();
alert(2);
});
在你的代码中,事件传播确实被停止了。然而,在 DOM 树上没有进一步的事件处理程序,因此一开始就没有事件传播可观察。你所看到的是同一元素上两个独立处理 click
事件的事件处理程序。
在这里的示例中,父元素 (div.outer
) 确实有一个事件处理程序,传播在到达该处理程序之前停止了。如果不停止传播,你将看到该事件处理程序被调用。
$(document).on("click", ".outer", function(e) {
alert(3);
});
$(document).on("click", ".el", function(e) {
alert(2);
});
你可能在寻找 stopImmediatePropagation()
,它可以阻止同一元素上的进一步事件处理程序被调用。例如:
$(document).on("click", ".el", function(e) {
e.stopImmediatePropagation();
alert(2);
});
$(document).on("click", ".el", function(e) {
e.stopImmediatePropagation();
alert(3);
});
在这种情况下,目标元素上的第二个 click
处理程序阻止了进一步的 click
处理程序的调用,但不会影响已经被调用的第一个 click
处理程序。
编辑: 你的更新后的代码展示了一个稍微不同的问题。在原始问题中,通过事件委托,事件处理程序附加到了哪个 DOM 对象?是 document
。它位于 DOM 层次结构中更高,并且在父元素已经处理其内联 click
处理程序之后才被触发。
如果直接将 click
处理程序附加到元素上,你会看到差异:
$(".stop").on("click", function(e) {
e.stopPropagation();
alert(2);
});
另一个正在变化的问题的编辑: 你仍然基本上遇到了相同的问题。一个 click
处理程序位于元素本身上,另一个位于 document
对象上。后者不会在前者之前被处理。
在这种情况下,将元素附加到 DOM 后,可能会使事情稍微复杂化,你可能需要在附加元素后将 click
处理程序附加到元素本身。例如,这会停止传播:
$(document).ready(function() {
var el = '<div class="el" onclick="alert(1);"><div class="stop">X</div>Click</div>';
$("body").append(el);
$(".stop").on("click", function(e) {
e.stopPropagation();
alert(2);
});
})
这里的关键区别是,jQuery 的 click
处理程序不是附加到 document
或依赖事件委托/传播。它是直接附加到目标元素,因此需要在元素添加到 DOM 后附加。
英文:
> why the e.stopPropagation() function does not work?
It does work. Observe:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
$(document).on("click", ".outer", function(e) {
alert(3);
});
$(document).on("click", ".el", function(e) {
e.stopPropagation();
alert(2);
});
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="outer">
<div class="el" onclick="alert(1)";>Click</div>
</div>
<!-- end snippet -->
In your code the event propagation is indeed being stopped. However, there are no further event handlers up the DOM tree so there's no propagation to observe in the first place. What you have are two separate click
handling events on the same element, both of which are being processed independently.
In the example shown here, a parent element (div.outer
) does have an event handler, and the propagation stops before it reaches that handler. Without stopping propagation, you'd see that event handler invoked:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
$(document).on("click", ".outer", function(e) {
alert(3);
});
$(document).on("click", ".el", function(e) {
alert(2);
});
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="outer">
<div class="el" onclick="alert(1)";>Click</div>
</div>
<!-- end snippet -->
You might be looking for stopImmediatePropagation()
instead? This will prevent further event handlers from being invoked on the same element. For example:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
$(document).on("click", ".el", function(e) {
e.stopImmediatePropagation();
alert(2);
});
$(document).on("click", ".el", function(e) {
e.stopImmediatePropagation();
alert(3);
});
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="el" onclick="alert(1)";>Click</div>
<!-- end snippet -->
In this case The second click
handler on the target element stopped further click
handlers on that same element from being processed. Note that this has no effect on the first click
handler, which was already invoked by then.
Edit: Your updated code demonstrates a slightly different problem. (Which was being obscured in the original code by the original problem addressed above.)
Notice how you are attaching your jQuery event handler. Which DOM object are you attaching it to?... document
. Which is much further up the DOM hierarchy and isn't reached until after the parent element has already processed its inline click
handler.
If you attach a click
handler directly to the element, you can see the difference:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
$(".stop").on("click", function(e) {
e.stopPropagation();
alert(2);
});
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="el" onclick="alert(1)">
<div class="stop">X</div>
Click
</div>
<!-- end snippet -->
Another edit for the ongoing moving target...
You're still essentially running into the same issue. One click handler is on the element itself, another is on the document
object. The latter won't be processed before the former.
Appending the elements to the DOM after the fact may indeed complicate things a little in this case, and you may need to attach the click handler to the element(s) themselves after appending them. For example, this stops the propagation:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
$(document).ready(function() {
var el = '<div class="el" onclick="alert(1);"><div class="stop">X</div>Click</div>';
$("body").append(el);
$(".stop").on("click", function(e) {
e.stopPropagation();
alert(2);
});
})
<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
</body>
<!-- end snippet -->
The key difference here is that the jQuery click
handler isn't being attached to the document
or relying on event delegation/propagation in the first place. It's being attached directly to the target element, and as such needed to be attached after the element is added to the DOM.
答案2
得分: 2
First, you made a typo. class
only has 2 s
s in it.
That aside, the event starts on the div that you click. It then propagates to the div with the onclick
attribute (triggering that), then continues up the DOM until it hits the document
object and triggers the event handler bound with jQuery
at which point stopPropagation
is called and it stops.
If you want to prevent the onclick
attribute triggering then you need to handle the event in the capture phase. I don't think jQuery supports that so you'll need to use native DOM instead.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
document.addEventListener("click", function(e) {
if (!e.target.closest(".stop")) return;
e.stopPropagation();
alert(2);
}, {
capture: true
});
<!-- language: lang-html -->
Click
<!-- end snippet -->
英文:
First, you made a typo. class
only has 2 s
s in it.
That aside, the event starts on the div that you click. It then propagates to the div with the onclick
attribute (triggering that), then continues up the DOM until it hits the document
object and triggers the event handler bound with jQuery
at which point stopPropagation
is called and it stops.
If you want to prevent the onclick
attribute triggering then you need to handle the event in the capture phase. I don't think jQuery supports that so you'll need to use native DOM instead.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
document.addEventListener("click", function(e) {
if (!e.target.closest(".stop")) return;
e.stopPropagation();
alert(2);
}, {
capture: true
});
<!-- language: lang-html -->
<div class="el" onclick="alert(1)" ;>
<div class="stop">X</div>
Click
</div>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论