深圳幻海软件技术有限公司 欢迎您!

事件委托原理及应用(必学知识点总结)

2023-03-03

目录事件委托与事件对象事件冒泡与事件捕获添加事件处理的方法DOM2Events事件流事件对象常用属性和方法事件委托的应用(实现hover悬停变色效果)事件委托与事件对象事件冒泡与事件捕获事件流:用于描述页面接收事件的顺序。以下是事件流的两种不同方案:事件冒泡:事件由最具体的元素逐级向上传递到最不具体

目录
  • 事件委托与事件对象
    • 事件冒泡与事件捕获
    • 添加事件处理的方法
    • DOM2 Events事件流
    • 事件对象常用属性和方法
    • 事件委托的应用(实现hover悬停变色效果)

事件委托与事件对象


事件冒泡与事件捕获

事件流:用于描述页面接收事件的顺序。以下是事件流的两种不同方案:

事件冒泡:事件由最具体的元素逐级向上传递到最不具体的元素

事件捕获:事件由最不具体的元素逐级向下传递到最具体的元素

以上的两种事件流方案是截然相反的,分别由IE开发团队和Netscape开发团队提出。


添加事件处理的方法

HTML事件处理程序:利用特定HTML标签的事件属性(<input>)。代码如下:

<input type="button" value="测试" onclick="test()">
<script>
let test = () => { // 利用标签属性添加事件
    console.log('已被点击')
}
</script>

DOM0事件处理程序:利用DOM节点自带的事件属性。代码如下:

<input type="button" value="测试" id="test">
<script>
let test = document.querySelector('#test')
test.onclick = () => { // 利用onlick属性添加事件
    console.log('已被点击')
}
</script>

DOM2事件处理程序(推荐):利用DOM节点(继承自EventTarget)的添加事件监听器方法。代码如下:

<input type="button" value="测试" id="test">
<script>
let test = document.querySelector('#test')
test.addEventListener('click', ()=>{ // 利用添加事件监听器方法
    console.log('已被点击')
})
</script>

说明:在网页DOM编程中的继承关系:EventTarget<=Node<=Element。因此上面的test变量拥有addEventListener方法


DOM2 Events事件流

捕获阶段Document=>Element html=>Element body=>Element div

冒泡阶段Element div=> Element body=>Element html=>Document

我们首先了解EventTarget.addEventListener(type, listener, options)这个方法的一些内部参数:

type:监听事件的类型

listener:接收一个回调函数,事件触发后会执行。

options:里面有比较多的可选项参数,这里我们利用capture(布尔值:默认为false)这个参数。表示监听的事件在捕获阶段会触发listener执行。

接下来我们利用上面的方法还原上面DOM2事件流的捕获阶段与冒泡阶段,如下:

<div style="cursor: pointer">我是一个事件,请点击验证</div>
<script>
// 捕获阶段
document.addEventListener("click", () => {
    console.log("捕获阶段1:Document") // document
}, true)
document.documentElement.addEventListener("click", () => {
    console.log("捕获阶段2:Element html") // html
}, true)
document.body.addEventListener("click", () => {
    console.log("捕获阶段3:Element body") // body
}, true)
document.querySelector("div").addEventListener("click", () => {
    console.log("捕获阶段4:Element div") // div
}, true)
// 冒泡阶段
document.querySelector("div").addEventListener("click", () => {
    console.log("冒泡阶段4:Element div") // div
}, false)
document.body.addEventListener("click", () => {
    console.log("冒泡阶段5:Element body") // body
}, false)
document.documentElement.addEventListener("click", () => {
    console.log("冒泡阶段6:Element html") // html
}, false)
document.addEventListener("click", () => {
    console.log("冒泡阶段7:Document") // document
}, false)
</script>

很明显,上面的代码验证了网页的事件触发会存在DOM2事件流这一执行过程。我们点击了事件,这个事件经历了由捕获阶段再到冒泡阶段的传递。


事件对象常用属性和方法

方法属性 说明
Event.target 只读 对事件原始目标的引用。
Event.type 只读 事件的类型,不区分大小写。
event.preventDefault 取消默认事件(如果该事件可取消)。
event.stopPropagation 停止冒泡,阻止事件在 DOM 中继续冒泡。

其中Event.target最为常用,具体指代触发了相应事件的Node节点目标。


事件委托的应用(实现hover悬停变色效果)

需求:实现一个列表,鼠标进入或离开都会使列表子元素的背景颜色改变。

如果没有事件委托,我们一般实现这个需求应该这样做。如下:

<div class="list" style="height: 400px; width: 400px;">
    <ul style="list-style: none; text-align: center;">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
</div>
<script>
let list = document.querySelectorAll('.list > ul > li');
// 遍历DOM集合,给每个li添加事件
list.forEach(element => {
    element.addEventListener('mouseover', () => {
        element.style.backgroundColor = 'green';
    })
    element.addEventListener('mouseout', () => {
        element.style.backgroundColor = '';
    })
});
</script>

我们遍历每个li元素并为其添加鼠标移入与移出事件。目前总共添加了八个事件处理程序。

注意:在JavaScript中,事件处理程序的数量会影响页面的整体性能。

因此对上述实现方式我们有必要采取措施优化。利用事件委托优化如下:

// 点击li元素后会通过事件冒泡机制触发ul添加的click事件。
<div class="list" style="height: 400px; width: 400px;">
    <ul style="list-style: none; text-align: center;">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
</div>
<script>
let list = document.querySelector('.list > ul');
// 直接给ul父元素添加事件即可
list.addEventListener('mouseover', (event) => {
    if (event.target.nodeName.toLowerCase() === 'li') {
        event.target.style.backgroundColor = 'green';
    }
})
list.addEventListener('mouseout', (event) => {
    if (event.target.nodeName.toLowerCase() === 'li') {
        event.target.style.backgroundColor = '';
    }
})
</script>

我们只给list元素添加了两个事件,同样实现了需求。如果采用原始方式,我们一共给这些li元素添加了八个事件。利用事件委托的方式进行网页性能的优化,其效果不言而喻。


参考

MDN-Event

JavaScript高级程序设计(第4版)