除了特定元素之外,我想对所有点击做一些事情.
我创建了一个非常简单的例子来演示这个问题:http://jsfiddle.net/nhe6wk77/.
我的代码:
$('body').on('click', ':not(a)', function () {
// do stuff
});
Run Code Online (Sandbox Code Playgroud)
我希望所有点击都<a>被忽略,但事实并非如此.
我做错了什么,或者这是jQuery方面的错误?
不,这不是一个错误,而是预期的行为.
事件一直在冒泡.通过单击a节点,您仍然会从节点触发它的父div节点事件.
阅读有关W3C DOM规范中事件冒泡的更多信息.只是寻找"泡沫".
您需要停止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();
});
Run Code Online (Sandbox Code Playgroud)
JSFiddle:http://jsfiddle.net/nhe6wk77/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');
}
});
Run Code Online (Sandbox Code Playgroud)
:not()选择器的使用在委托事件中受到尊重,但这是一种不常见的做法,因为事件冒泡DOM树可能会在此过程中多次触发处理程序.
在jQuery的API文档指出:
jQuery将事件从事件目标起泡到附加处理程序的元素(即最里面到最外层的元素),并为匹配选择器的路径上的任何元素运行处理程序.
注意短语"并运行与该选择器匹配的路径上的任何元素的处理程序".
在您的示例中,jQuery准确地没有在a元素上运行处理程序,但是当事件冒泡树时,它会为匹配的任何元素运行处理程序:not(a),这是路径中的每个其他元素.
这是一个明显的例子,展示了它是如何工作的:http://jsfiddle.net/gfullam/5mug7p2m/
$('body').on('click', ':not(a)', function (e) {
alert($(this).text());
});
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)
单击嵌套div的第一个块中的链接,将启动事件冒泡,但单击的a元素 - 即事件target- 不会触发处理程序,因为它与:not(a)选择器不匹配.
但是当事件通过DOM冒泡时,它的每个父节点 - 也就是事件currentTarget- 触发处理程序,因为它们匹配:not(a)选择器,导致处理程序运行两次.需要注意多次触发,因为它可能不是理想的结果.
同样,单击第二个嵌套div块中的按钮将启动事件冒泡,但这次事件target与:not(a)选择器匹配,因此它会立即触发处理程序.然后,当事件冒泡时,每个匹配选择器的父项也会触发处理程序,导致处理程序运行三次.
正如其他人所建议的那样,您需要绑定一个替代处理程序来停止a单击事件上的传播,或者target针对:not(a)处理程序内的选择器而不是委托选择器检查事件.