除了某个元素外,我想对所有点击做一些事情。
我创建了一个非常简单的示例来演示此问题:http://jsfiddle.net/nhe6wk77/。
我的代码:
$('body').on('click', ':not(a)', function () {
// do stuff
});
我希望忽略<a>
上的所有点击,但事实并非如此。
我做错了什么,或者这是jQuery方面的错误?
答案 0 :(得分:7)
不,这不是错误,而是预期的行为。
事件一直在冒泡。通过单击a
节点,您仍然可以从div
节点触发 parent 事件。
阅读more about event bubbling in the W3C DOM Specification。只需搜索“泡沫”。
您需要停止a
节点的事件传播。即:
$('body').on('click', ':not(a)', function () {
// do something effectively
alert('you should not see me when clicking a link');
});
$("a").click(function( event ) {
// do nothing effectively, but stop event bubbling
event.stopPropagation();
});
JSFiddle:http://jsfiddle.net/nhe6wk77/6/
答案 1 :(得分:6)
该代码中有很多内容并不明显。最重要的是,click
事件实际上附加到body
元素。由于该元素不是锚点,因此您将始终获得警报。 (事件委托之所以有效,是因为click
事件从a
到其所有祖先(包括body
)一直冒泡,直到达到document
。)
您要做的是检查event.target
。这将告诉您实际点击的元素,但实际的click
事件仍然绑定到body
元素:
$('body').on('click', function (e) { // e = event object
if ($(e.target).is(':not(a)')) {
alert('got a click');
}
});
答案 2 :(得分:5)
:not()
选择器的使用在委托事件中受到尊重,但这是一种不常见的做法,因为事件冒泡的DOM树可能会在此过程中多次触发处理程序。
jQuery将事件从事件目标起泡到附加处理程序的元素(即最里面到最外层的元素),并为该路径上与选择器匹配的任何元素运行处理程序。
注意短语“并为该路径上与选择器匹配的任何元素运行处理程序”。
在您的示例中,jQuery准确地没有在a
元素上运行处理程序,但是当事件冒泡树时,它会为匹配:not(a)
的任何元素运行处理程序,路径中的其他元素。
以下是一个显示其工作原理的明显示例:http://jsfiddle.net/gfullam/5mug7p2m/
$('body').on('click', ':not(a)', function (e) {
alert($(this).text());
});
<div class="outer">
<div class="inner">
<a href="#">Click once, trigger twice</a>
</div>
</div>
<div class="outer">
<div class="inner">
<button type="button">Click once, trigger thrice</button>
</div>
</div>
单击嵌套div的第一个块中的链接,将启动事件冒泡,但单击的a
元素 - 也就是事件target
- 不会触发处理程序,因为它没有' t匹配:not(a)
选择器。
但是当事件通过DOM冒泡时,它的每个父节点 - 事件currentTarget
- 触发处理程序,因为它们匹配:not(a)
选择器,导致处理程序运行两次。多次触发是需要注意的事项,因为它可能不是理想的结果。
同样,单击嵌套div的第二个块中的按钮将启动事件冒泡,但这次事件target
与:not(a)
选择器匹配,因此它会立即触发处理程序。然后当事件冒泡时,每个匹配选择器的父项也会触发处理程序,导致处理程序运行三次。
正如其他人所建议的那样,您需要绑定一个替代处理程序来停止a
点击事件的传播,或者检查事件target
对照处理程序中的:not(a)
选择器而不是委托选择器。
答案 3 :(得分:3)
$("body").click(function(e) {
if($(e.target).is('a')){
e.preventDefault();
return;
}
alert("woohoo!");
});
检查点击的目标。这样你就不需要绑定另一个事件了。