一、DOM事件模型
如图所示
1. 事件捕获
捕获是从上到下,事件先从window对象,然后再到document(对象),然后是html标签然后是body标签,然后按照普通的html结构一层一层往下传,最后到达目标元素。
2. 事件冒泡
与事件捕获正好相反,是从下往上一层一层的传。
3. 执行过程
先是执行事件捕获,再执行事件冒泡;事件捕获不可以取消,事件冒泡可以取消;开发者自己决定把监听函数放在事件捕获还是事件冒泡上;
4. 绑定事件API
addEventListener
IE5: xxx.attachEvent('onclick',fn) //冒泡
网景: xxx.addEventListener('click',fn) //捕获
W3C: xxx.addEventListener('click',fn,bool) //如果bool值是falsy值或者不传参数,事件就是冒泡事件;如果bool值是true则是捕获事件;
二、事件委托
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation)。
1. 优点
-
省监听数(省内存) 举例:如果要给100个按钮都要添加点击事件,就可以监听这100个按钮的祖先,等冒泡的时候判断target是不是这100个按钮中的一个
-
可以监听动态元素 在很多时候,我们需要通过用户操作动态的增删列表项元素,如果一开始给每个子元素绑定事件,那么在列表发生变化时,就需要重新给新增的元素绑定事件,给即将删去的元素解绑事件,如果用事件委托就会省去很多这样麻烦。
2. 实现方法
div1.addEventListener('click', (e)=>{ //给父元素添加click事件
const t = e.target
if(t.tagName.toLowerCase === 'button'){ //判断是否匹配目标元素
console.log('button被点击了')
console.log('被点击的内容是' + t.textContent)
}
})
3. 封装事件委托
要求: 写出一个函数on('click','#div1','button',fn) 当用户点击div1里面的button元素时调用fn函数
function on (eventType,element,selector,fn){
if(!(element instanceof Element)){ //如果element不是这个元素,就去找这个元素
element = document.querySlector(element)
}
element.addEventListener(eventType,(e)=>{
const t = e.target //获取到用户点击的元素
if(t.matches(selector)){ //matches检查元素是否是选择器
fn(e)
}
})
}
三、阻止默认动作
例如表单一点击提交按钮(submit)跳转页面、a标签默认页面跳转或是锚点定位等都是默认动作; 用event. preventDefault()方法阻止默认动作
四、阻止事件冒泡
event.stopPropagation() 方法阻止事件冒泡到父元素,阻止任何父事件处理程序被执行。
五、其他知识点
- e.target是用户操作的元素
- e.currentTarget是程序员监听的元素
- DOM事件不属于JS的功能,是浏览器提供的DOM功能;JS只是调用了DOM提供的addEventListener而已;DOM事件和JS事件属于平行的一个等级
参考文章:《DOM事件机制》