假如在一個 ul 中有著 100 個 li,當鼠標點擊一個 li 的時候,便執(zhí)行一些動作。完成以上功能必須給每個 li 都綁定一個事件嗎?顯然這么做有點浪費,畢竟要綁定 100 次,倘若能只綁定一次,就好了——說得便是事件委托。
事件委托(Event Delegation)是 JavaScript 中十分常用的方法之一。事件委托允許你不監(jiān)聽那些具體(li)的元素,相應的把事件綁定在其父元素(ul)上。例如下面這段代碼:
<ul id="parent-list">
<li class="child">Item 1</li>
<li class="child">Item 2</li>
<li class="child">Item 3</li>
<li class="child">Item 4</li>
<li class="child">Item 5</li>
<li class="child">Item 6</li>
</ul>
如之前所說,分別給每個 li 的綁定事件,不僅看上去有些浪費,而且一旦再添加新的 li 的時候,還要再給新加入的元素綁定事件,沒法實現(xiàn)動態(tài)監(jiān)聽。但是父元素 ul 是不變的,給它綁定監(jiān)聽事件再合適不過。
關鍵問題是:怎么找到那個目標元素?請看下面代碼:
//找到父元素,給其綁定事件
document.getElementById("parent-list").addEventListener("click", function(e) {
//找到真正的目標元素
if(e.target && e.target.nodeName === "LI") {
console.log(e.target.innerText);
}
});
監(jiān)聽 ul,一旦子元素事件冒泡到父元素,通過 event.target 檢查是否找到了目標元素。如果沒找到,就忽略這次事件;找到了,則輸出目標元素內(nèi)容??梢渣c擊示例查看結(jié)果:
<a class="jsbin-embed" >JS Bin on jsbin.com</a><script src="http://static.jsbin.com/js/embed.min.js?3.41.10"></script>
這只是簡單的使用原生 JS 實現(xiàn)事件委托,其中還有許多不足——如果 li 內(nèi)還有子元素怎么辦?
<ul id="parent-list">
<li class="child">
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
</ul>
</li>
<li class="child">Item 2</li>
<li class="child">Item 3</li>
<li class="child">Item 4</li>
<li class="child">Item 5</li>
<li class="child">Item 6</li>
</ul>
情況有兩點不同:
- 雖然點擊的元素時
li.child li,但實際的目標元素為li.child - 需要判斷點擊的元素是否在
li.child之內(nèi)
對于第一點,使用 Element.matches() 或許會是個好主意[1]。第二點的解決辦法是:循環(huán)檢查點擊元素的父元素,止于監(jiān)聽元素。如下示例:
<a class="jsbin-embed" >JS Bin on jsbin.com</a><script src="http://static.jsbin.com/js/embed.min.js?3.41.10"></script>
當然,還有許多 DOM 庫在處理事件和元素時,有著更強大的功能,在實際應用中也很有幫助。
參考鏈接
-
較新的瀏覽器才支持
Element.matches(),可能會有兼容性的問題。 ?