多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## 事件委托 “过多事件处理程序”的解决方案是使用**事件委托**。事件委托利用事件冒泡,可以只使用一个事件处理程序来管理一种类型的事件。例如,click 事件冒泡到 document。这意味着可以为整个页面指定一个 onclick 事件处理程序,而不用为每个可点击元素分别指定事件处理程序。比如有以下 HTML: ```html <ul id="myLinks"> <li id="goSomewhere">Go somewhere</li> <li id="doSomething">Do something</li> <li id="sayHi">Say hi</li> </ul> ``` 这里的 HTML 包含 3 个列表项,在被点击时应该执行某个操作。对此,通常的做法是像这样指定 3 个事件处理程序: ```js let item1 = document.getElementById("goSomewhere"); let item2 = document.getElementById("doSomething"); let item3 = document.getElementById("sayHi"); item1.addEventListener("click", (event) => { location.href = "http:// www.wrox.com"; }); item2.addEventListener("click", (event) => { document.title = "I changed the document's title"; }); item3.addEventListener("click", (event) => { console.log("hi"); }); ``` 如果对页面中所有需要使用 onclick 事件处理程序的元素都如法炮制,结果就会出现大片雷同的只为指定事件处理程序的代码。使用事件委托,只要给所有元素共同的祖先节点添加一个事件处理程序,就可以解决问题。比如: ```js let list = document.getElementById("myLinks"); list.addEventListener("click", (event) => { let target = event.target; switch(target.id) { case "doSomething": document.title = "I changed the document's title"; break; case "goSomewhere": location.href = "http:// www.wrox.com"; break; case "sayHi": console.log("hi"); break; } }); ``` 这里只给`<ul id="myLinks">`元素添加了一个 onclick 事件处理程序。因为所有列表项都是这个元素的后代,所以它们的事件会向上冒泡,最终都会由这个函数来处理。但事件目标是每个被点击的列表项,只要检查 event 对象的 id 属性就可以确定,然后再执行相应的操作即可。相对于前面不使用事件委托的代码,这里的代码不会导致先期延迟,因为只访问了一个 DOM 元素和添加了一个事件处理程序。结果对用户来说没有区别,但这种方式占用内存更少。所有使用按钮的事件(大多数鼠标事件和键盘事件)都适用于这个解决方案。 只要可行,就应该考虑只给 document 添加一个事件处理程序,通过它处理页面中所有某种类型的事件。相对于之前的技术,事件委托具有如下优点。 * document 对象随时可用,任何时候都可以给它添加事件处理程序(不用等待 DOMContentLoaded 或 load 事件)。这意味着只要页面渲染出可点击的元素,就可以无延迟地起作用 * 节省花在设置页面事件处理程序上的时间。只指定一个事件处理程序既可以节省 DOM 引用,也可以节省时间 * 减少整个页面所需的内存,提升整体性能 最适合使用事件委托的事件包括:click、mousedown、mouseup、keydown 和 keypress。mouseover 和 mouseout 事件冒泡,但很难适当处理,且经常需要计算元素位置(因为 mouseout 会在光标从一个元素移动到它的一个后代节点以及移出元素之外时触发)。