当事件处理程序过多时,可以使用事件委托来解决。事件委托利用了 事件冒泡 ,只指定一个事件处理程序,就可以管理某一类的所有事件。例如,click 事件会一直冒泡到 document 层。也就是说,我们可以为整个页面指定一个 onclick 事件处理程序,而不必给每个元素单独添加事件处理程序,尤其当要监听的子元素过多时。
<ul id='father'>
<li id='son1'>aaaaa</li>
<li id='son2'>bbbbbb</li>
<li id='son3'>cccccccc</li>
...
</ul>
<script>
var item1 = document.getElementById("son1");
var item2 = document.getElementById("son2");
var item3 = document.getElementById("son3");
EventUtil.addHandler(item1, "click", function(event){
location.href = "aaaaaaaaaaaa";
});
EventUtil.addHandler(item2, "click", function(event){
document.title = "bbbbbbbbbbbbbbb";
});
EventUtil.addHandler(item3, "click", function(event){
alert("ccccccccc");
});
</script>
如果这是一个包含成百上千个子元素的列表,对所有可单击的元素都用上述的写法,那会有数不清的重复代码。如果使用事件委托,只需要在 DOM 树中尽量最高的层次上添加一个事件处理程序,就可以解决。
<script>
let item = document.getElementById('father');
item.addEventListener('click',function(e){
let itemNode = e.target
switch(e.target.id){
case 'son1':
document.title = 'aaaa';
break;
case 'son2':
alert('bbbbbbbbb');
break;
}
})
</script>
由于所有的列表项都是这个元素的子节点,并且会触发事件冒泡,然后通过 id 来判断执行哪段逻辑。
相比于传统做法的优点:
- 整个页面占用的内存空间更少,提升了整体的性能;
- 在页面中设置事件监听所需的时间更少,只添加一个事件监听所需的 DOM 引用更少,所需时间也更少;
- 只要可单击的元素呈现在页面上,就可以立即具备相应的功能。也就是很快可以被访问;
页面元素与 JavaScript 代码的交互(绑定监听事件)越多,页面执行起来就越慢。除了使用 事件委托 限制建立的连接的数量。另外也可以在不需要的时候, 移除事件处理程序。
比如我们使用 removeChild() 、replaceChild()方法,或者使用 innerHTML 替换页面中的某一部分时,带有事件处理程序的元素被移除了,但之前添加到元素中的事件处理程序有可能无法被当作垃圾回收。
<div id='myDiv'>
<input type='button' value='click me' id='btn'>
</div>
<script type='text/javascript'>
let btn = document.getElementById('btn');
btn.onclick = function(){
// 一些操作
document.getElementById('myDiv').innerHTML = '把按钮替换成了文字";
}
</script>
当按钮被移除后,绑定的事件仍然与按钮保持着引用关系。有的浏览器可能将对元素和对绑定事件的引用都保存在内存中。如果我提前知道要移除这个元素,那可以在移除之间,解除事件绑定。
<div id='myDiv'>
<input type='button' value='click me' id='btn'>
</div>
<script type='text/javascript'>
let btn = document.getElementById('btn');
btn.onclick = function(){
// 一些操作
btn.onclick = null;
document.getElementById('myDiv').innerHTML = '把按钮替换成了文字";
}
</script>