DOM事件机制和事件委托

345 阅读2分钟

DOM事件机制和事件委托

一、简介

事件流是一个事件沿着特定数据结构传播的过程。冒泡和捕获是事件流在DOM中两种不同的传播方式。

事件流有三个阶段

  • 事件捕获阶段
  • 处于目标阶段
  • 事件冒泡阶段

事件捕获和事件冒泡

事件捕获:事件从最外层父元素到最里层子元素的顺序触发,如document > html > body > div > p。

事件冒泡:事件从最里层子元素到最外层父元素的顺序触发,如p < div < body < html < document。

v2.png

因为有捕获和冒泡两种传播方式,W3C制定了一个标准可以让我们自己选择使用哪种传播方式。我们在使用addEventListener监听事件时,addEventListener('click',fn,bool) ,如果第三个参数bool不传或者为falsy,那么我们会在冒泡阶段调用fn,如果第三个参数bool为true,那么我们会在捕获阶段调用fn。

image.png

target和currentTarget

e.target为用户操作的元素

e.currentTarget是程序员监听的元素

<div>
   <span>我是文字</span>
 </div>

假设我们监听的是div元素,但用户实际点击的是文字内容,那么

e.target指向span元素

e.currentTarget指向div元素

event.stopPropagation()阻止事件冒泡

当事件使用 event.stopPropagation() 方法将阻止事件冒泡到其父元素,代码示例如下:

<div id="parent" style="width: 200px; height: 200px; border: 1px solid springgreen;">
        <div id="son" style="width: 100px; height: 100px; border: 1px solid blue;">son</div>
    </div>
    <script>
        parent.addEventListener('click', () => {
            console.log('我是parent');
        })
        son.addEventListener('click', (e) => {
            console.log('我是son');
            e.stopPropagation(); // 中断事件冒泡
        })
    </script>

image.png

event.preventDefault()阻止默认事件

如果调用这个方法,默认事件行为将不再触发。什么是默认事件?例如表单一点击提交按钮 submit 跳转页面、 a 标签默认页面跳转或是锚点定位等。

举个例子:

a 标签添加点击事件,当用户点击文字就阻止 a 标签的默认页面跳转功能

 <a href="https://www.baidu.com" id="x">百度一下</a>
    <script>
        x.addEventListener('click', (e) => {
            e.preventDefault();
        })
    </script>

image.png

二、事件委托

由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方法叫做事件委托。

举个例子:

有一个div元素,div元素里有大量的button按钮,我们需要在点击每个button按钮的时候响应一个事件,怎么做?

<div id="container">
    <button>1</button>
    <button>2</button>
    <button>3</button>
    <button>4</button>
    <button>5</button>
    <button>6</button>
    <button>7</button>
    <button>8</button>
    <button>9</button>
    <button>10</button>
  </div>

实现的JS代码:

// 监听父元素 div#container
container.addEventListener('click',(e)=>{
    const t = e.target
    if(t.matches('button')){
    console.log('点击了button')
    }
})

思路:

  1. 首先监听父元素
  2. 然后根据浏览器传进去的事件信息,拿到当前点击元素e.target
  3. 再判断当前点击元素是不是button,如果是,就输出log语句

综上所述利用事件委托可以有效减少内存消耗,提高性能。