先實作一個小功能:在點選 HTML 的按鈕後,把訊息輸出到控制台。
為了實現這個小功能,你需要選擇按鈕,然後再用addEventListener()
方法來附加事件監聽器:
<button id="buttonId">Click me</button> <script> document.getElementById('buttonId') .addEventListener('click', () => console.log('Clicked!')); </script>
以上就是偵聽單一元素(尤其是按鈕)上事件的方式。
如果需要監聽多個按鈕上的事件呢?以下是一個可能的實作:
<div id="buttons"> <button class="buttonClass">Click me</button> <button class="buttonClass">Click me</button> <!-- buttons... --> <button class="buttonClass">Click me</button> </div> <script> const buttons = document.getElementsByClassName('buttonClass'); for (const button of buttons) { button.addEventListener('click', () => console.log('Clicked!')); } </script>
按鈕清單被迭代為 for (const button of buttons)
,並且每個按鈕都被附加了一個新的偵聽器。另外在清單中的按鈕被新增或刪除後,你必須也要手動刪除或附加事件監聽器。
有沒有更好的方法?
幸運的是,如果我們使用「事件委託」模式的話,偵聽多個元素上的事件只需要一個事件偵聽器。
事件委託使用事件傳播機制的細節。想要要了解事件委託的工作原理,應該先了解什麼是事件傳播。
當你點擊下面 html 中的按鈕:
<html> <body> <div id="buttons"> <button class="buttonClass">Click me</button> </div> </body> </html>
點擊事件會觸發多少個元素?毫無疑問,按鈕本身會收到點擊事件。而且所有按鈕的祖先,甚至包括 document
和 window
物件也會收到。
點選事件的傳播分三個階段:
擷取階段 —— 從window
,document
和根元素開始,事件向下擴散至目標元素的祖先
目標階段 —— 事件在使用者點擊的元素上觸發
冒泡階段-最後,事件冒泡通過目標元素的祖先,一直到根元素document
和window
。
addEventListener
方法的第三個參數captureOrOptions
# :
element.addEventListener(eventType, handler[, captureOrOptions]);
使你可以捕捉來自不同階段的事件。
captureOrOptions
參數,或參數為false
或{capture:false}
,那麼偵聽器將會擷取目標(target)和冒泡階段(bubble phases)的事件true
或{capture:true}
,那麼偵聽器將會偵聽捕獲階段(capture phase)的事件。 透過下面的程式碼,你會偵聽到在 元素上發生的捕獲階段的點擊事件:
document.body.addEventListener('click', () => { console.log('Body click event in capture phase'); }, true);
在這個Codesandbox 示範中,當點擊按鈕時,你可以在控制台中查看事件的傳播方式。
那麼事件傳播是怎麼幫助捕捉多個按鈕事件的呢?
這個演算法很簡單:把事件偵聽器附加到按鈕的父級,並在點擊按鈕時捕捉冒泡事件。這就是事件委託的工作方式。
讓我們用事件委託來捕獲多個按鈕上的點擊:
<div id="buttons"> <!-- Step 1 --> <button class="buttonClass">Click me</button> <button class="buttonClass">Click me</button> <!-- buttons... --> <button class="buttonClass">Click me</button> </div> <script> document.getElementById('buttons') .addEventListener('click', event => { // Step 2 if (event.target.className === 'buttonClass') { // Step 3 console.log('Click!'); } }); </script>
開啟Codesandbox 演示,然後點擊任一按鈕,你會看到 'Click!'
訊息被記錄到控制台。
事件委託的想法很簡單。你不需要把委託事件監聽器直接附加到按鈕上,而是可以委託父監聽 <div id="buttons">。點選按鈕時,父元素的偵聽器將會捕捉<strong>冒泡事件</strong>(還記得前面所說事件傳播嗎?)。 <p>使用事件委託需要3個步驟:</p>
<h4>步驟1:決定要監視事件的元素的父級元素</h4>
<p>在上面的例子中,<code>
是按鈕的父元素。
document.getElementById('buttons') .addEventListener('click', handler)
將事件偵聽器附加到按鈕的父元素。此事件偵聽器也會對按鈕點擊做出反應,因為按鈕點擊事件冒泡通過祖先元素(由於事件傳播)。
单击按钮时,将会用event
对象参数调用处理函数。属性 event.target
访问在其上调度了事件的元素,在例子中是一个按钮:
// ... .addEventListener('click', event => { if (event.target.className === 'buttonClass') { console.log('Click!'); } });
顺便说明一下,event.currentTarget
指向事件侦听器直接附加到的元素。在例子中,event.currentTarget
是 <div id="buttons">。<p>现在,你可以看到事件委托模式的好处:事件委托仅需要一个事件侦听器,而不必像本文最初那样将侦听器附加到每一个按钮上。</p>
<h2 id="item-4">总结</h2>
<p>当发生点击事件(或传播的任何其他事件)时:</p>
<ul>
<li>事件从 <code>window
、document
、根元素向下传播,并经过目标元素的祖先(捕获阶段);
document
和 window
(冒泡阶段)。该机制称为事件传播。
事件委托是一种有用的模式,因为你可以只需要用一个事件处理程序就能侦听多个元素上的事件。
使用事件委托需要三个步骤:
确定要监视事件的元素的父级元素
把将事件侦听器附加到父元素
用 event.target
选择目标元素
更多计算机编程相关知识,请访问:编程视频!!
以上是深入淺析JS中的事件委託的詳細內容。更多資訊請關注PHP中文網其他相關文章!