今天同事遇到这样一个问题,找我解决。
他希望点击整个DIV都可以响应点击事件,但是有些交互元素需要排除掉。如:点击链接页面跳转、点击按钮响应事件等)。
这是一个关于事件冒泡的问题,那便从事件冒泡写起。

事件冒泡

在一个元素上触发事件,如果此元素定义了处理程序,那么此次事件就会被捕获,根据程序进行该事件的处理。否则这个事件会根据DOM树向父节点逐级传播,如果从始至终都没有被处理,那么最终会到达document或window根元素。

阻止事件冒泡

W3C标准调用事件对象的stopPropagation()方法,IE可以设置对象的cancelBubble属性为true;

在Jquery中的事件方法都带有event参数,这是一个符合W3C标准的事件对象,且兼容IE,可以使用event.stopPropagation()阻止冒泡。更简单的,直接return false;,等价于event.stopPropagation()加上event.preventDefault()

在原生JS中,事件对象要区别对待。

function cancelEvent(e) {
if(e) {
e.stopPropagation(); //非IE
} else {
window.event.cancelBubble = true; //IE
}
}

阻止多个子元素的事件

综上所述,想要链接和按钮元素不响应父节点事件,便要为所有这些元素注册事件,编写阻止事件冒泡的代码。

现在的代码可以这样写:

var div = $('#div');
div.click(function(){
// do...
});
div.on('click', 'a,button,input', function(event){
event.stopPropagation(); // 或 return false;
});

这当然是可以解决问题的。
可对于处女座的我完全无法接受平白无故多写了一段莫名奇妙的代码。

于是我想到了event对象。

  • event.target 返回事件的目标节点(触发该事件的节点)。
  • event.target.tagName 目标节点的标签名

把上面两个事件合并处理之:

$('#div').on('click', function(event){
var tag = event.target.tagName;
if(tag!='A' && tag!='BUTTON' && tag!='INPUT'){
// do...
}
});