本文长期更新,如有错误,还请指正!
关注一下不迷路 =.=
概念
盒子多层嵌套时,当你点击盒子,浏览器实际上并不知道点的是哪个,它的一层层去查,查到有点击事件则执行。
历史初期查找方案:
ie是从最内层开始查,直到查到最外层,即为冒泡流;
而网景提出的是从最外层开始查,即为捕获流;
现阶段方案:
W3C提出了都支持方案,即:先捕获后冒泡。
然而一个事件绑定后并不会触发2次,你决定事件放在捕获阶段触发或冒泡阶段触发,但ie低版本只支持冒泡流,为了兼容建议使用冒泡流。
事件绑定的方式
- dom里直接配置属性
<div onclick="show()">按钮</div>
考虑,js和html的分离不建议使用此方式
- js操作dom属性绑定
document.getElementById('btn').onclick = function(e){
...
}
- 事件监听
非ie8-
绑定:target.addEventListener(type, fn, true/false)
移除:target.removeEventListener(type, fn, true/false)
type
指事件类型;fn
指执行函数;设为true指使用捕获流(实际上目前第3个参数可以是个对象,后期有需要再补充)
缺点:
-
removeEventListener
第二个参数fn必不可少,且fn不可是匿名函数也不可改变其上下文,否则无效 - 很难一次性移除全部事件
区别:除了可以设置捕获,事件监听还可以绑定多个事件,而使用属性绑定只能有一个。
document.getElementById('e').addEventListener('click',function (event) {
console.log('e',event)
},true);
ie8-
绑定:target.attachEvent(type, fn)
移除:target.detachEvent(type, fn)
ie是冒泡流,需要注意的是fn里的this指向window(正常指向触发事件的元素,这很有用)
注:
- 各种浏览器默认的都是冒泡,避免使用捕获
- 一般情况使用第二种方式,除非需要多次绑定同一个事件再使用
addEventListener
event 对象
使用注意:var e= event || window.event
(火狐使用window.event会报错)。
表示在DOM中发生的任何事件,在事件处理函数被传入,主要关注2个属性:currentTarget
target
event.currentTarget / this 绑定事件的元素
event.target / event.srcElement(ie8-) 开始触发的元素(从哪个元素开始触发的;冒泡是最内层的盒子,捕获则相反)
//加上div#f内套div#e
document.getElementById('e').addEventListener('click',function (e) {
console.log(e.target); //div#f
console.log(e.currentTarget); //div#e
},true);
注:有时可能只希望触发一个事件或者事件委托,可以使用此方式
阻止默认事件
比如用在阻止radio/checkbox选中
- 对于onclick绑定方式:
return false
- 对于监听绑定方式:
event.preventDefault()
-
window.event.returnValue = false
(ie8-)
事件委托
即把事件绑定在父节点上,通常用在子节点不存在时的情况,或者子节点多且绑定相同事件的情况
//如下,div#f不存在的情况下绑定好事件
document.getElementById('e').addEventListener('click',function (e) {
var e=e||window.event;
var target=e.target||e.srcElement;
if(target.id==='f'){
alert('find children f')
}
});
document.getElementById('e').innerHTML='<div id="f"></div>';
注意
- 冒泡或捕获对脱离文档流的元素无效,所以遮罩层(绝对定位)有效果