DOM事件和事件委托

136 阅读3分钟

一、DOM事件模型

如图所示

image.png

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事件机制》