Tancky's  Blog

理解JavaScript中的事件委托

在我们平常工作或学习编写JS代码的过程中,经常会做的一件事就是给某个元素绑定事件。例如鼠标点击,移入,移出等等,以响应用户的某种行为,举个栗子:

1
2
3
4
var btn=document.getElementById("btn");
btn.onclick=function(){
alert("hello world!");
};

上述的栗子是当用户点击某个按钮时会弹出对话框显示”hello world” 。但是在某些情况下,我们期望页面上的一些元素响应用户同样的动作,举个例子。在用户点击列表的每一项时,将其内容显示在div里。例如这样:

1
2
3
4
5
6
7
8
9
10
<ul class="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>100</li>
</ul>
<div class="list-show"></div>

用JQuery我们可以这么做:

1
2
3
$('.list li').on('click', function() {
$('.list-show').html($(this).html());
});

其实就是给列表的每一项(100个)分别绑定了点击事件。这样做的弊端在于,增加了内存,因为\$(.list li)里有100个li对象。同时降低了代码性能,因为$(’.list li’)会搜索ul下所有的li元素。

那么有没有更好的方法呢?

当然有,那就是事件委托!上面代码也可以这样写:

1
2
3
$('.list').on('click', 'li', function() {
$('.list-show').html($(this).html());
}); //jquery都是用on绑定事件。jquery规定on()中的第二个参数如果是dom元素,则为事件委托,否则为正常的事件绑定。

基本概念

  • 什么是事件委托
    事件委托又称事件代理(话说之前我以为这两个是不一样的概念…),用网上很经典的一个场景来描述就是取快递:

有三个同事预计会在周一收到快递。为签收快递,有两种办法:一是三个人在公司门口等快递;二是委托给前台MM代为签收。现实当中,我们大都采用委托的方案(公司也不会容忍那么多员工站在门口就为了等快递)。前台MM收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款。这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台MM也会在收到寄给新员工的快递后核实并代为签收。

这里其实还有2层意思的:

第一,现在委托前台的同事是可以代为签收的,即程序中的现有的dom节点是有事件的;

第二,新员工也是可以被前台MM代为签收的,即程序中新添加的dom节点也是有事件的。

  • 事件委托的原理

    事件委托其实就是利用的事件冒泡的原理,而事件冒泡就是事件开始时由最具体的元素(文档中嵌套层次最深的那个节点接收),然后逐级向上传播到最不为具体的节点(文档)。

    在本文最开始举例的代码中可以看出:

    将li元素的点击事件委托给其父元素ul。这么做之所以行得通,是因为事件具有冒泡的特点,当内层元素的某个事件被触发,事件会一级一级冒泡到更外层元素。当外层元素被绑定事件且被触发时,判断事件的来源即event.target是否是目标元素li,如果是就执行回调。上面的代码等价于:

1
2
3
4
5
6
7
8
9
10
function showText(text) {
$('.list-show').html(text);
}
$('.list').on('click', function(event) {
var $target = $(event.target);
if ($target.is('li')) {
showText($target.html());
}
});
  • 事件委托的优点

A.使用事件委托可以明显减少dom的操作次数,优化性能和节约内存空间。
B.新添加的元素依然会有之前添加的事件(即新来的员工也能收到快递)。在上例中,如果通过AJAX向列表增加新项,新添加项仍能响应用户点击。在页面动态变化后,不需要重新检索元素和绑定事件。

本文完!

撒花!

热评文章