作为我学习设计模式的开端,今天总结一下JavaScript的代理模式。 代理模式是JavaScript中最常出现的设计模式,因为在JavaScript中的表现非常直接,方便。
我们来举个栗子。
<ul id ="parent-list" > <li id ="child-0" > Item 0</li > <li id ="child-1" > Item 1</li > <li id ="child-2" > Item 2</li > <li id ="child-3" > Item 3</li > <li id ="child-4" > Item 4</li > <li id ="child-5" > Item 5</li > <li id ="child-6" > Item 6</li > </ul >
我们现在有这么一个列表,我们需要在用户点击li标签的时候做出响应。你可能会给每个li标签绑定事件。
for (var i = 0 ; i <=6 ; i++) { document .getElementById('child-' + i).addEventListener('click' , function ( ) { }); }
当然你可能是用更高级的写法来降低耦合度,比如:
var list = document .getElementById('parent-list' );var listItems = list.getElementsByTagName('li' );var listLength = list.length;for (var i = 0 ; i < listLength; i++) { var listItem = listItems[i]; listItem.onclick = function ( ) { } }
且不说闭包可能带来的问题,这样写是没错,除非…
假设现在我们需要频繁动态增删改li标签,那么相应的增加删除事件监听将会是个噩梦。更好的解决方式是使用代理模式,把所有li标签上的事件监听全都转移到一个公共元素上,然后通过某种标记判断当前事件来源即可。
那么,去哪里找这么一个公共元素呢? 我们可以使用他们的最小公父亲(我瞎说的)#parent-list
,我们都知道js事件有捕获和冒泡两个过程。 当你点击了目标对象,事件会通过冒泡逐层向外传递,并且事件对象中保存着目标对象的副本,所以使用事件代理,我们可以通过处理事件对象简单地判断事件来源。
修改我们的代码:
document .getElementById("parent-list" ).addEventListener("click" , function (e ) { if (e.target && e.target.tagName.toLowerCase() == "li" ) { console .log("List item " , e.target.id.replace("child-" ), " was clicked!" ); } });
总结
优势:
大量减少了绑定事件的数量,代码执行效率更高! DOM结构更改,不需要重新绑定事件
劣势:
javaScript中部分事件并没有冒泡,比如blur
,focus
等 代理的代码也可能会非常耗时,所以最好保持事件处理的代码尽量简洁
相关资源
[Event delegation] —— 事件代理常用情景
[How JavaScript Event Delegation Works] —— JavaScript事件代理
[JavaScript学习总结(九)事件详解] —— 来自SegmentFault
如需转载,请注明出处:http://w3ctrain.com/2015/10/14/javascript-event-delegation/