likes
comments
collection
share

DOM必修课之了解事件对象及事件传播机制

作者站长头像
站长
· 阅读数 25

啥是事件对象及事件传播机制?在JavaScript中事件对象提供了与事件相关的信息,使开发者能够根据事件的具体情况做出相应的处理。而事件传播机制则决定了事件在DOM结构中的传递方式,使得开发者可以在不同层级的DOM元素上捕获和处理事件,实现交互和响应的灵活性和可控性。下面我们就围绕DOM中的事件来对其深入了解了解。

事件对象

  • 事件对象是由浏览器在事件触发时所创建的对象,

    这个对象封装了事件相关的各种信息

  • 通过事件对象可以获取到事件的详细信息

    比如:鼠标的坐标、键盘的按键等

  • 浏览器在创建事件对象后,会将事件对象作为响应函数的参数传递,

    所以我们可以在事件的回调函数中定义一个形参进行接收事件对象

例如:

box.addEventListener('click',function(event)=>{
    console.log(event)  // 当我们点击box所对应的DOM元素时event事件对象会被输出
})

其中的event为此次点击事件的事件对象

  • 在DOM中存在着多种不同类型的事件对象
  • 所有的事件对象有一个共同的祖先:Event
  • event对象的属性较多具体可参考:Event - Web API | MDN (mozilla.org)

事件的冒泡

我们在处理事件相关操作时,事件冒泡是常会遇到或用到的一种机制。事件的冒泡是指当一个元素上的事件被触发时,该事件不仅会在当前元素上触发,还会向其父元素及祖先元素传播。

事件冒泡过程

假设我们在网页中有这样一段结构

DOM必修课之了解事件对象及事件传播机制

<div class="box1">
    <div class="box2">
        <div class="box3">
            
        </div>
    </div>
</div>

当我们给它们添加事件时:

let box1 = document.querySelector('.box1')
let box2 = document.querySelector('.box2')
let box3 = document.querySelector('.box3')

box1.addEventListener('click',function(event){
    console.log("我是box1")
})
box2.addEventListener('click',function(event){
    console.log("我是box2")
})
box3.addEventListener('click',function(event){
    console.log("我是box3")
})

在以上的代码结构基础之上,

  • 当我们点击蓝色部分时我们可以看到控制输出的只有我是box1

  • 当我们点击红色部分时我们可以看到控制台输出了我是box2我是box1

  • 当我们点击绿色部分时我们可以看到控制台输出了我是box3我是box2我是box1

通过以上例子我们可以看到,当我们点击一个子元素时,不仅会触发自身(box3)的点击事件,同时也触发了其父元素(box2)及祖先元素(box1)的点击事件,且它们的顺序时从里向外的,正如其名冒泡(一层一层地往外冒)

阻止事件冒泡

在有点时候我们并不希望事件冒泡的存在,所以我们可以通过事件对象上的event.stopPropagation()去阻止事件冒泡。

box2.addEventListener('click',function(event){
    console.log("我是box2")
    event.stopPropagation()
})

// 在将box2中添加了停止冒泡方法后,
// 点击蓝色(box1)时,输出'我是box1'
// 点击红色(box2)时,输出'我是box2'
// 点击绿色(box3)时,输出'我是box3','我是box2'

我们可以发现的是当box2的点击事件触发后事件的传导就已经被提前结束了,box3的没有被阻止所以传递到了box2。

同时我们要注意的是事件的冒泡跟位置无关只跟结构有关。

<div class="box1">
    <div class="box2">
        <div class="box3" style="left: 300px;"></div>
    </div>
</div>

DOM必修课之了解事件对象及事件传播机制

当我们改变box3的位置后我们点击box3(绿色方块)同样会触发box1与box2的点击事件

  • 事件的冒泡就是指事件的向上传导
  • 当元素的某个事件被触发后,其祖先元素上的相同事件也会同时被触发
  • 冒泡的存在大大简化了代码的编写,但是在一些场景下我们并不希望冒泡 我们可以通过事件对象停止事件冒泡

事件对象中的DOM元素

在事件对象中有多种获取事件有关DOM元素的方式,其中主要有:

  • event.target:以该方式获取的DOM对象为触发事件的对象。
  • event.currentTarget:以该方式获取的DOM对象为绑定事件的对象。
  • this:同event.currentTarget特别注意的是当事件所绑定的回调函数为箭头函数时this为全局对象window)。
box1.addEventListener('click',function(event){
    console.log(event.target,event.currentTarget)
})

同上,当我们将代码改成上述内容,当点击红色(box2)时,输出为<div class="box2"></div>,<div class="box1"></div>,分别代指类名为box2的DOM元素(触发事件的对象)与类名为box1的DOM元素(绑定事件的对象)。

事件的委派

假设有这样一个场景:

<button id="btn">增加一个按钮</button>
<ul>
    <li><button>按钮1</button></li>
    <li><button>按钮2</button></li>
    <li><button>按钮3</button></li>
</ul>
let btns = document.querySelectorAll('li button')
btns.forEach(item=>{
    item.addEventListener('click',(event)=>{
        console.log('我被点击了')
    })
})
let btn = document.getElementById('btn')
let ul = document.querySelector('ul')
btn.addEventListener('click',()=>{
    let num = ul.querySelectorAll('li button').length+1
    ul.insertAdjacentHTML(
        'beforeend',
        `<li><button>按钮${num}</button></li>`
    )
})

DOM必修课之了解事件对象及事件传播机制

列表中有一组按钮,我想给每一个红色的按钮都添加一个点击事件,首先我们可以通过循环每个button元素来给每个按钮添加点击事件。

但是当我点击添加一个按钮后,多添加的点击按钮却没有被添加点击事件。我们很容易想到的是,只要我们获取到新添加的节点重新添加点击事件就行了。

这样虽然可以,但稍显麻烦,这时我们就可以巧妙地利用事件委派来解决了

我们可以将以上代码改为:

let ul = document.querySelector('ul')
let btn = document.getElementById('btn')
btn.addEventListener('click',()=>{
    let num = ul.querySelectorAll('li button').length+1
    ul.insertAdjacentHTML(
        'beforeend',
        `<li><button>按钮${num}</button></li>`
    )
})
ul.addEventListener('click',(event)=>{
    if([...ul.querySelectorAll('li button')].includes(event.target)){
        console.log('我被点击了')
    }
})

我们可以看到的是我们将事件写在了ul的点击事件上,并通过判断是否触发事件,就相当于ul替按钮完成了事件的触发,这并是事件的委派(将button上的事件委派到ul元素上),委派就是将本该绑定给多个元素的事件统一绑定到其父元素(或祖先元素)上进行处理。

以上只是做了个简单的示例,总结起来事件的委派有不少优点,主要有:

  1. 减少内存消耗和提高页面响应速度。尤其在动态添加大量子元素的场景下,无需为新元素重复绑定事件监听器。
  2. 只需在父元素上编写一次事件处理逻辑,即可管理所有子元素的事件,易于维护和扩展。
  3. 对于动态添加或删除的子元素,事件委托可以自动处理这些新元素的事件,无需额外的事件绑定操作。

事件的传播机制

在DOM中事件的传播可分为三个阶段:

  1. 捕获阶段(由祖先元素向目标元素进行事件捕获):事件从根节点开始,沿着DOM层次向下传播,直至到达事件的实际目标元素。

  2. 目标阶段(触发事件的对象):事件达到目标元素后,在目标元素上触发相应的事件处理函数。

  3. 冒泡阶段(由元素向祖先元素进行事件冒泡):事件从目标元素开始,再次向外层元素传播,直到达到DOM树的根节点。

默认情况下,事件不会在捕获阶段触发, 如果希望在捕获阶段触发事件, 可以将addEventListener的第三个参数设置为true

一般情况下我们不希望在捕获阶段触发事件,所以通常不设置第三个参数。


本次的分享就到此结束啦!谢谢你的阅读😊😊😊,有错误的地方还望指正。

转载自:https://juejin.cn/post/7375054926584021003
评论
请登录