"过多事件处理程序"的解决方案
场景一:你要给100个按钮添加点击事件,咋办?
-
“过多事件处理程序“的解决方案是使用事件委托。事件委托利用事件冒泡,可以只使用一个事件处理程序来管理一种类型的事件。例如,click事件冒泡到document。这意味着可以为整个页面指定一个onclick事件处理程序,而不用为每个可点击元素分别指定事件处理程序。比如有以下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个事件处理程序:
let item1 = document.getElementById("goSomewhere"); let item2 = document.getElementById("doSomething"); let item3 = document.getElementById("sayHi"); item1.addEventListener("click", (event) => { location.href = "https://www.baidu.com"; }); item2.addEventListener("click", (event) => { document.title = "I am changing the document's title"; }); item3.addEventListener("click", (event) => { console.log("hi"); })如果对页面中所有需要使用onclick事件处理程序的元素都如法炮制,结果就会出现大片雷同只为指定事件处理程序的代码,例如如果有100个button元素呢。使用事件委托,只要给所有元素共同的祖先节点添加一个事件处理程序,就可以解决问题。比如:
let list = document.getElementById("myLinks"); list.addEventListener("click", (event) => { let target = event.target; switch(target.id) { case "goSomewhere": location.href="https://www.baidu.com"; break; case "doSometing": document.title = "I am changing the document's title"; break; case "sayHi": console.log("hi"); break; } }); -
另一个栗子:通常用于为许多相似的元素添加相同的处理
<button data-toggle-class="subscribe">Show the subscription form</button> <form class="subscribe" hidden>Your mail: <input type="email" /></form> <form class="subscribe" hidden> Your password: <input type="password" /> </form> <script> document.addEventListener("click", function (event) { let cls = event.target.dataset.toggleClass; if (!cls) return; let elems = document.getElementsByClassName(cls); for (let i = 0; i < elems.length; i++) { elems[i].hidden = !elems[i].hidden; } }); </script>
监听动态元素的解决方案
场景二:你要监听目前不存在的元素的点击事件,咋办?
-
监听祖先,等点击的时候看看是不是我想要监听元素即可。
<body> <div id="div1"></div> </body> <script> setTimeout(() => { const btn = document.createElement("button"); btn.textContent = "Click me"; div1.appendChild(btn); }, 1000); div1.addEventListener("click", (event) => { let t = event.target; if (t.tagName.toLowerCase() === "button") { console.log("button clicked!"); } }); </script>
小结
- 算法
- 在容器(container)上放一个处理程序
- 在处理程序中 —— 检查源元素
event.target。 - 如果事件发生在我们感兴趣的元素内,那么处理该事件。
- 好处
- 简化初始化并节省内存:无需添加许多处理程序。
- 可以监听动态元素。
- 局限性
- 首先,事件必须冒泡。而有些事件不会冒泡。此外,低级别的处理程序不应该使用
event.stopPropagation()。
- 首先,事件必须冒泡。而有些事件不会冒泡。此外,低级别的处理程序不应该使用
- 推荐阅读:
现代JavaScript教程 - 事件委托