Chen Yangjian's Blog

Carpe diem - Seize the day

事件代理以及它的好处

| Comments

不是什么新东西了,昨天做的分享里头需要讲到,又把几个知识点翻出来看了一下,这篇博客总结得不错,摘译一些。

事件代理利用的是事件冒泡机制,在事件,例如点击触发时,是从 DOM 树最底端的阶段开始往顶端冒泡,事件对象贯穿这个生命周期。入门事件绑定的时候,绑定与处理是这样的:

old.js
1
2
3
4
5
6
7
8
var button = document.getElementById('J_button');

button.onclick = function(e) {
   e = e || window.event;
   var target = e.target || e.srcElement;

   // handles target
};

这在要绑定、处理的节点多了之后有点难办的,尤其是列表、表格这种场景,在 for 循环的时候,有个经典的 js gotcha:

wrong.js
1
2
3
4
5
6
// 错误代码
for (i = 0; i < anchors.length; i++) {
    anchors[i].onclick = function(e) {
        alert(i);
    };
}

不管点那个锚点,alert 出来的都是 anchors.length -1,熟悉 js 的都会告诉你,这是因为闭包的关系,因为等你点击任意锚点的时候,这个 for 循环执行已毕,当前上下文,也就是 onclick 所在的闭包,里头的 i 已经是 anchors.length -1。

而如果用事件代理的方式,则强迫你放弃闭包中的这些循环变量:

delegate.js
1
2
3
4
5
6
7
8
anchors_box.onclick = function(e) {
   e = e || window.event;
   var target = e.target || e.srcElement;

   if (target.tagName.toLowerCase() === 'a') {
       alert(a);
   }
};

如果需要 i,则需要在事件处理时去实时获取,或者预处理一下,将 i 放到它们的属性里头去。两者对比,采用事件代理方式的好处显得清楚明了:

  1. 绑定起来更加方便
  2. 减少闭包使用,从而降低可能不必要的内存占用
  3. 对代理节点的 innerHTML 做修改,不需要重新绑定
  4. 在事件监听节点比较多的情况下,特别是重型的 OPOA,跑得更顺畅

参考文章

Comments