JS事件委託(事件代理)

2020-07-16 10:05:08
在 JavaScript 中,事件委託(delegate)也稱為事件託管或事件代理,就是把目標節點的事件係結到祖先節點上。這種簡單而優雅的事件註冊方式是基於事件傳播過程中,逐層冒泡總能被祖先節點捕獲。

這樣做的好處:優化程式碼,提升執行效能,真正把 HTML 和 JavaScript 分離,也能防止出現在動態新增或刪除節點過程中註冊的事件丟失的現象。

範例1

下面範例使用一般方法為列表結構中每個列表專案系結 click 事件,單擊列表專案,將彈出提示對話方塊,提示當前節點包含的文字資訊。但是,當我們為列表框動態新增列表專案之後,新新增的列表專案沒有繫結 click 事件,這與我們的願望相反。
<button id="btn">新增列表專案</button>
<ul id="list">
    <li>列表專案1</li>
    <li>列表專案2</li>
    <li>列表專案3</li>
</ul>
<script>
    var ul = document.getElementById("list");
    var lis = ul.getElementsByTagName("li");
    for (var i = 0; i < lis.length; i ++) {
        lis[i].addEventListener('cluick', function (e) {
            var e = e || window.event;
            var target = e.target || e.srcElement;
            alert(e.target.innerHTML);
        }, false);
    }
    var i = 4;
    var btn = document.getElementById("btn");
    btn.addEventListener("click", function() {
        var li = document.createElement("li");
        li.innerHTML = "專案列表" + i++;
        ul.appendChild(li);
    });
</script>

範例2

下面範例借助事件委託技巧,利用事件傳播機制,在列表框 ul 元素上繫結 click 事件,當事件傳播到父節點 ul 上時,捕獲 click 事件,然後在事件處理常式中檢測當前事件響應節點型別,如果是 li 元素,則進一步執行下面程式碼,否則跳出事件處理常式,結束響應。
<button id="btn">新增專案列表</button>
<ul id="list">
    <li>列表專案1</li>
    <li>列表專案2</li>
    <li>列表專案3</li>
</ul>
<script>
    var ul = document.getElementById("list");
    ul.addEventListener('click', function(e) {
        var e = e || window.event;
        var target = e.target || e.srcElement;
        if (e.target && e.target.nodeName.toUpperCase()=="LI") {
            alert(e.target.innerHTML);
        }
    }, false);
    var i = 4;
    var btn = document.getElementById("btn");
    btn.addEventListener("click", function () {
        var li = document.createElement("li");
        li.innerHTML = "專案列表" + i++;
        ul.appendChild(li);
    });
</script>
當頁面存在大量元素並且每個元素註冊了一個或多個事件時,可能會影響效能。存取和修改更過的 DOM 節點時,程式就會更慢;特別是事件連線過程都發生在 load(或 DOMContentReady)事件中時,對任何一個富互動網頁來說,這都是一個繁忙的時間段。另外,瀏覽器需要儲存每個事件控制代碼的記錄,也會佔用更多記憶體。