在W3C的标准下.事件有两个模型.
事件冒泡和事件捕获
除非情况特殊,我们在默认情况下都是使用的事件冒泡模式.
el.addEventListener('click', function () {
console.log('xxxx')
} , false)
取消事件冒泡
事件会冒泡需要几个前提
- 首先,模式使用的是事件冒泡模式(而不是事件捕获)
- 几个元素之间包含嵌套关系.
- 几个嵌套元素中,点击的元素的外部元素[恰好]也绑定了同类型事件响应函数.
其实,很多情况下,我们根本就不需要执行所谓的取消事件冒泡
原因也很简单:
- 大多数HTML元素都只是为了展示数据的.一般有事件交互的很少.
- 一般有事件交互的都是单纯的那个交互的元素绑定了事件响应函数,而和它有嵌套关系的元素虽然事件存在,但是没有绑定事件响应函数,所以就没有必要执行阻止事件冒泡
- 有很多事件压根就不支持事件冒泡,比如常用的表单元素的
input
,focus
,select
等.
但是如果实际情况属于下面的场景的话,可能就需要执行阻止事件冒泡了.
-
有两个(N)元素,它们是嵌套关系.
-
两个(N)元素都绑定了
click
事件响应函数,且使用的是事件冒泡模式. -
在点击内部元素时,只希望执行点击了的那个元素的
click
事件响应函数.
<div class="parent">
<div class="child"></div>
</div>
parent.addEventListener('click', function () {
console.log('父元素的事件响应函数被子元素的事件冒泡给触发了')
}, false)
child.addEventListener('click', function () {
console.log('child clicked')
}, false)
默认情况下,事件冒泡从内往外传递.
这里我们点击了内部的 .child
的 DIV
元素.
事件冒泡到了 .parent
的 DIV
元素.
巧的是 .parent
也绑定了 click
事件响应函数.(然而多数情况是,外部元素一般不会这么巧也会绑定同样的 click 事件响应函数,所以绝大多数情况,我们不需要阻止所谓的取消事件冒泡)
于是它们就形成了一个我们不想要的因为事件冒泡儿产生的结果.
child clicked
父元素的事件响应函数被子元素的事件冒泡给触发了
事件参数
取消事件冒泡,也有一个前提.
前提是每一个事件响应函数在执行时,都有一个 e
表示事件参数.
它保存了当前事件产生的一些必要数据(包括事件源对象,位置坐标等信息)
parent.addEventListener('click', function () {
console.log('父元素的事件响应函数被子元素的事件冒泡给触发了')
}, false)
child.addEventListener('click', function (e) {
e.stopPropagation() // 取消事件冒泡.
console.log('child clicked')
}, false)
e
是当前事件响应函数带过来的事件信息对象.
stopPropagation
是阻止事件冒泡的方法.
调用 e.stopPropagation()
方法,就可以阻止事件往外传递.
值的一提的是:
stopPropagation
是 W3C 标准里定义的阻止事件冒泡的方法.
既然是 W3C 标准,那么肯定有的浏览器不是这么来阻止事件冒泡的.
对的,说的就是你 IE9 以及以下版本.
你说,如果仅仅只是一个方法不一致也就罢了...
对于 IE9 以及以下版本 获取事件对象的方式也不一样.
在老版本IE中,事件对象,不是事件响应函数带的那个事件参数.
而是使用 window.event
来获取.
同时,阻止事件冒泡也不是 stopPropagation()
,而是 window.event.cancelBubble=true
.
所以,如果是在一个IE低版本浏览器里.
阻止事件冒泡的写法是下面这样.
child.onclick = function () {
var event = window.event
event.cancelBubble = true
}
or
child.attachEvent('onclick', function () {
var event = window.event
event.cancelBubble = true
})
取消事件冒泡兼容方法
function cancelBubble (e) {
let e = e || window.event
if (e.stopPropagation) {
e.stopPropagation()
} else {
e.cancelBubble = true
}
}
网友评论