JS:事件委托
事件委托
-
事件流
事件流描述的是从页面中接收事件的顺序。---JS高级程序设计(第3版)
DOM Level 2 Events
规定的事件流有三个阶段:①事件捕获阶段、②处于目标阶段、③事件冒泡阶段 -
事件委托
当需要添加的事件过多时,可以使用事件委托,而事件委托实际上利用了事件冒泡的特性。
使用事件委托还需了解事件对象(
event
):在触发DOM上的某个事件时,会产生一个事件对象event
,这个对象中包含着所有与事件有关的信息。在此仅需知道在
DOM
标准中,event
拥有一个target
属性表示事件目标。event.target
是一个触发事件的对象的引用。它与event.currentTarget
不同, 当事件处理程序在事件的冒泡或捕获阶段被调用时。(mdn)具体
Event
详情可以查看MDN:Event
如果你想要在大量子元素中单击任何一个都可以运行一段代码,您可以将事件监听器设置在其父节点上,并将事件监听器气泡的影响设置为每个子节点,而不是每个子节点单独设置事件监听器。(mdn)
以下面的html代码为例:
<ul id="list"> <li id="one">do something</li> <li id="two">do something</li> <li id="three">do something</li> </ul>
当需求是单击上面每个
li
标签都会执行各种操作时,使用事件委托是较好的选择。// bad (逐个 li 添加事件) let item1 = document.getElementById('one'); let item2 = document.getElementById('two'); let item3 = document.getElementById('three'); item1.addEventListener('click', function(){...}, false); item1.addEventListener('click', function(){...}, false); item1.addEventListener('click', function(){...}, false); // event delegation (事件委托) let list = document.getElementById('list'); list.addEventListener('click', function(e){ if (e.target && e.target.nodeName == 'LI') { switch (e.target.id) { case 'one': do something; break; case 'two': do something; break; case 'three': do something; break; } } }, false);
注意:当
li
标签被如p
、div
等撑满时,点击的target
为p
标签而不是li
标签会导致无法正确执行click
事件。以下面的html代码为例:
<ul id="list"> <li id="one">do something</li> <li id="two">do something</li> <!-- 这里的 li 里面有个 p 标签 --> <li id="three"><p>do something</p></li> </ul>
这样的情况可以使用递归 or 循环来处理,毕竟事件委托是利用事件冒泡的特性。
//递归 let list = document.getElementById('list'); list.addEventListener('click', function(e){ eventDelegation(e.target); }, false); function eventDelegation(target) { if (target && target.nodeName == 'LI') { switch (target.id) { case 'one': do something; return; case 'two': do something; return; case 'three': do something; return; } } return eventDelegation(target.parentNode); }
-
使用事件委托的优点
a.减少DOM操作,使事件处理时间减少。
b.减少内存空间的使用,提升性能。
因为在JavaScript中,每个函数都是对象,对象越多,占用的内存也就越多,合理使用事件委托可以减少内存的占用。
-
注意事项
比较适合使用事件委托的事件:
click
、mousedown
、mouseup
等,而如mouseout
、mouseover
等则不太适合使用事件委托(虽然mouseout
这些事件也冒泡,但通常需要确定元素的位置,所以不太推荐使用事件委托)。另外不会冒泡的事件是不适合使用事件委托的。