10分钟搞懂事件委托

117 阅读2分钟

当我们在项目中,会遇到很多需要创建事件、监听并处理事件的情况。比方说,我们有一个如下的HTML页面,是一个网页版的todoList,现在的需求就是当我们的用户在点击每一项todo时,会触发一个事件监听,并且处理一些事情。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
	<h1>todo-app</h1>
	<ul id="todo-list">
		<li class="item">待办事项1:该吃早饭了</li>
		<li class="item">待办事项2:该吃午饭了</li>
		<li class="item">待办事项3:该吃晚饭了</li>
		<li class="item">待办事项4:该睡觉了</li>
	</ul>
</body>

</html>

首先,如果不用事件委托的话我们就需要用for循环,为每一个todo项绑定上一个事件监听器。

document.addEventListener('DOMContentLoaded', () => {
    let todoList = document.getElementById('todo-list');
    let items = todoList.getElementsByClassName('item');

    for (let item of items) {
        item.addEventListener('click', (e)=>{
            alert("You have clicked this item: " + item.innerHTML)
        })
    }
})

但是,我们试想一下实际情况,假设这位用户创建了每天都创建100条todo,并且他都没完成,那么一个月之后,可能就会有3000条todos,那么如果我们还是用这种方式,就需要绑定3000个单独的事件监听器,想想就觉得这样会耗费很多资源。

针对这种场景,我们就需要换一种方式,我们只给他的根容器邦定一个事件监听器,当我们点击这个根容器的的时候,我们可以捕获到点击的元素节点e.target,然后我们再对这个元素节点绑定上需要的事件监听器。本质上这个就是把所有子节点都统一委托给他的根容器的行为,就是事件委托

document.addEventListener("DOMContentLoaded", () => {
    let todo-list = document.getElementById("todo-list");

    app.addEventListener('click', (e) => {
        if (e.target && e.target.nodeName === 'LI') { // 我们可以打印一下e,看看e.target.nodeName到底是什么样子的。
            let item = e.target;
            alert("this is what you clicked:" + item.innerHTML)
        }
    })
})

通过这种方式,我们可以直接把事件监听委托给根容器,根据不同类型的节点,调用不同的事件监听器:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="container">
        <h1>todo-app</h1>
        <ul id="todo-app">
		<li class="item">待办事项1:该吃早饭了</li>
		<li class="item">待办事项2:该吃午饭了</li>
		<li class="item">待办事项3:该吃晚饭了</li>
		<li class="item">待办事项4:该睡觉了</li>
        </ul>

        <h1>readme</h1>
        <p>事件委托1</p>
        <p>事件委托2</p>
        <p>事件委托3</p>
        <p>事件委托4</p>
    </div>

</body>

</html>
document.addEventListener("DOMContentLoaded", () => {
    let container = document.getElementById("container");

    container.addEventListener("click", (e) => {
        if (e.target && e.target.nodeName === "LI") {
            let item = e.target;
            alert("You have just clicked: " + item.innerHTML)
        };

        if (e.target && e.target.nodeName === "P"){
            let item = e.target;
            console.log("You have just clicked: " + item.innerHTML)
        }
    })
})

参考自:segmentfault.com/a/119000001…