事件委托
基本概念
事件代理(Event Delegation),又称之为事件委托。是JavaScript中常用绑定事件的常用技巧。顾名思义,“事件代理”即是把原本需要绑定在子元素的响应事件委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡
事件冒泡
前面提到事件委托的原理是DOM元素的事件冒泡,那么事件冒泡是什么呢?
一个事件触发后,会在子元素和父元素之间传播(propagation)。这种传播分成三个阶段
如上图所示,事件传播分成三个阶段:
捕获阶段:从window对象传导到目标节点(上层传到底层)称为“捕获段”(capture phase)。
目标阶段:在目标节点上触发,称为“目标阶段”
冒泡阶段:从目标节点传导回window对象(从底层传回上层),称为“冒泡阶段”(bubbling phase)。事件代理即是利用事件冒泡的机制把里层所需要响应的事件绑定到外层
事件委托的有点
- 可以大量节省内存占用,减少事件注册,比如在ul上代理所有li的click事件就非常棒
<ul class="list">
<li>time1</li>
<li>time2</li>
<li>time3</li>
<li>time4</li>
........
<li>time n/li>
</ul>
//代表中间还有无数个li标签
- 可以实现当新增子对象时无需再次对其绑定(动态绑定事件)
假设上述的例子中列表项li就几个,我们给每个列表项都绑定了事件;
在很多时候,我们需要通过 AJAX 或者用户操作动态的增加或者删除列表项li元素,那么在每一次改变的时候都需要重新给新增的元素绑定事件,给即将删去的元素解绑事件;
如果用了事件委托就没有这种麻烦了,因为事件是绑定在父层的,和目标元素的增减是没有关系的,执行到目标元素是在真正响应执行事件函数的过程中去匹配的;所以使用事件在动态绑定事件的情况下是可以减少很多重复工作的
基本示例
<ul id="myLinks">
<li id="goSomewhere">Go somewhere</li>
<li id="doSomething">Do something</li>
<li id="sayHi">Say hi</li>
</ul>
JavaScript原生实现事件委托
var myLinks = document.getElementById("myLinks");
var item1 = document.getElementById("goSomewhere");
var item2 = document.getElementById("doSomething");
var item3 = document.getElementById("sayHi");
myLinks.addEventListener("click", function (event) {
var target = event.target;
switch (target.id) {
case "doSomething":
document.title = "事件委托";
break;
case "goSomewhere":
location.href = "http://www.baidu.com";
break;
case "sayHi": alert("hi");
break;
}
})
jQuery事件delegate()实现事件委托
delegate() 方法为指定的元素(属于被选元素的子元素)添加一个或多个事件处理程序,并规定当这些事件发生时运行的函数。
格式:$(selector).delegate(childSelector, event, data, function)
参数 描述
childSelector 必需,规定要附加事件处理程序的一个或多个子元素。
event 必需,规定附加到元素的一个或多个事件。由空格分隔多个事件值。必须是有效的事件。
data 可选,规定传递到函数的额外数据。
function 必需,规定当事件发生时运行的函数。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://lib.sinaapp.com/js/jquery/2.0.2/jquery-2.0.2.min.js"></script>
</head>
<body>
<ul id="myLinks">
<li id="goSomewhere">Go somewhere</li>
<li id="doSomething">Do something</li>
<li id="sayHi">Say hi</li>
</ul>
<script>
$(document).ready(function () {
$("#myLinks").delegate("#goSomewhere", "click", function () {
location.href = "http://www.baidu.com";
});
});
</script>
</body>
</html>
事件委托封装
function delegate(element, eventType, selector, fn) {
element.addEventListener(eventType, e => {
let el = e.target
while (!el.matches(selector)) {
if (element === el) {
el = null
break
}
el = el.parentNode
}
el && fn.call(el, e, el)
})