大宇宇宇
发布于 2025-08-30 / 13 阅读
0
0

什么是事件代理?应⽤场景?

#JS

是什么

事件代理,俗地来讲,就是把⼀个元素响应事件( click 、 keydown ......)的函数委托到另⼀个元素

前⾯讲到,事件流的都会经过三个阶段: 捕获阶段 -> ⽬标阶段 -> 冒泡阶段,⽽事件委托就是在冒泡阶段完成

事件委托,会把⼀个或者⼀组元素的事件委托到它的⽗层或者更外层元素上,真正绑定事件的是外层元素,⽽不是⽬标元素

当事件响应到⽬标元素上时,会通过事件冒泡机制从⽽触发它的外层元素的绑定事件上,然后在外层元素上去执⾏函数

下⾯举个例⼦:

⽐如⼀个宿舍的同学同时快递到了,⼀种笨⽅法就是他们⼀个个去领取

较优⽅法就是把这件事情委托给宿舍⻓,让⼀个⼈出去拿好所有快递,然后再根据收件⼈⼀ 分发给每个同学

在这⾥,取快递就是⼀个事件,每个同学指的是需要响应事件的 DOM 元素,⽽出去统⼀领取快递的宿舍⻓就是代理的元素

所以真正绑定事件的是这个元素,按照收件⼈分发快递的过程就是在事件执⾏中,需要判断当前响应的事件应该匹配到被代理元素中的哪⼀个或者哪⼏个

应⽤场景

如果我们有⼀个列表,列表之中有⼤量的列表项,我们需要在点击列表项的时候响应⼀个事件

<ul id="list">
   <li>item 1</li>
   <li>item 2</li>
   <li>item 3</li>
   ......
   <li>item n</li>
</ul>

如果给每个列表项⼀ 都绑定⼀个函数,那对于内存消耗是⾮常⼤的

// 获取⽬标元素
const lis = document.getElementsByTagName("li")
// 循环遍历绑定事件
for (let i = 0; i < lis.length; i++) {
lis[i].onclick = function(e){
console.log(e.target.innerHTML)
}
}

这时候就可以事件委托,把点击事件绑定在⽗级元素 ul 上⾯,然后执⾏事件的时候再去匹配⽬标元素

// 给⽗层元素绑定事件
document.getElementById('list').addEventListener('click', function (e) {
    // 兼容性处理
    var event = e || window.event;
    var target = event.target || event.srcElement;
    // 判断是否匹配⽬标元素
    if (target.nodeName.toLocaleLowerCase === 'li') {
        console.log('the content is: ', target.innerHTML);
    }
});

还有⼀种场景是上述列表项并不多,我们给每个列表项都绑定了事件

但是如果⽤⼾能够随时动态的增加或者去除列表项元素,那么在每⼀次改变的时候都需要重新给新增的元素绑定事件,给即将删去的元素解绑事件

如果⽤了事件委托就没有这种⿇烦了,因为事件是绑定在⽗层的,和⽬标元素的增减是没有关系的,执⾏到⽬标元素是在真正响应执⾏事件函数的过程中去匹配的

举个例⼦:

下⾯ html 结构中,点击 input 可以动态添加元素

<input type="button" name="" id="btn" value="添加" />
<ul id="ul1">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
</ul>

使⽤事件委托

const oBtn = document.getElementById("btn");
const oUl = document.getElementById("ul1");
const num = 4;
//事件委托,添加的⼦元素也有事件
oUl.onclick = function (ev) {
ev = ev || window.event;
const target = ev.target || ev.srcElement;
if (target.nodeName.toLowerCase() == 'li') {
console.log('the content is: ', target.innerHTML);
}
};
//添加新节点
oBtn.onclick = function () {
num++;
const oLi = document.createElement('li');
oLi.innerHTML =
item ${num}
;
oUl.appendChild(oLi);
};

可以看到,使⽤事件委托,在动态绑定事件的情况下是可以减少很多重复⼯作的

总结

适合事件委托的事件有: click , mousedown , mouseup , keydown , keyup ,keypress

从上⾯应⽤场景中,我们就可以看到使⽤事件委托存在两⼤优点:

  • 减少整个⻚⾯所需的内存,提升整体性能

  • 动态绑定,减少重复⼯作

但是使⽤事件委托也是存在局限性:

  • focus 、 blur 这些事件没有事件冒泡机制,所以⽆法进⾏委托绑定事件

  • mousemove 、 mouseout 这样的事件,虽然有事件冒泡,但是只能不断通过位置去计算定位,对性能消耗⾼,因此也是不适合于事件委托的

如果把所有事件都⽤事件代理,可能会出现事件误判,即本不该被触发的事件被绑定上了事件


评论