1. 程式人生 > >前端系統複習之事件委託

前端系統複習之事件委託

1.概念

事件委託也叫事件代理,JavaScript高階程式設計上講:事件委託就是利用事件冒泡,只指定一個事件處理程式,就可以管理某一型別的所有事件。
用一個形象的例子說明:
有三個同事預計會在週一收到快遞。為簽收快遞,有兩種辦法:一是三個人在公司門口等快遞;二是委託給前臺MM代為簽收。現實當中,我們大都採用委託的方案(公司也不會容忍那麼多員工站在門口就為了等快遞)。前臺MM收到快遞後,她會判斷收件人是誰,然後按照收件人的要求籤收,甚至代為付款。這種方案還有一個優勢,那就是即使公司裡來了新員工(不管多少),前臺MM也會在收到寄給新員工的快遞後核實並代為簽收。

2.為什麼要用事件委託:

a.減少DOM操作,提高效能
b.讓新增的元素也繫結上事件
一般來說,dom需要有事件處理程式,我們都會直接給它設事件處理程式就好了,那如果是很多的dom需要新增事件處理呢?比如我們有100個li,每個li都有相同的click點選事件,可能我們會用for迴圈的方法,來遍歷所有的li,然後給它們新增事件,那這麼做會存在什麼影響呢?
在JavaScript中,新增到頁面上的事件處理程式數量將直接關係到頁面的整體執行效能,因為需要不斷的與dom節點進行互動,訪問dom的次數越多,引起瀏覽器重繪與重排的次數也就越多,就會延長整個頁面的互動就緒時間,這就是為什麼效能優化的主要思想之一就是減少DOM操作的原因;如果要用事件委託,就會將所有的操作放到js程式裡面,與dom的操作就只需要互動一次,這樣就能大大的減少與dom的互動次數,提高效能;
每個函式都是一個物件,是物件就會佔用記憶體,物件越多,記憶體佔用率就越大,自然效能就越差了(記憶體不夠用,是硬傷,哈哈),比如上面的100個li,就要佔用100個記憶體空間,如果是1000個,10000個呢,那隻能說呵呵了,如果用事件委託,那麼我們就可以只對它的父級(如果只有一個父級)這一個物件進行操作,這樣我們就需要一個記憶體空間就夠了,是不是省了很多,自然效能就會更好。

3.事件委託的原理:

事件委託是利用事件的冒泡原理來實現的,何為事件冒泡呢?就是事件從最深的節點開始,然後逐步向上傳播事件,舉個例子:頁面上有這麼一個節點樹,div>ul>li>a;比如給最裡面的a加一個click點選事件,那麼這個事件就會一層一層的往外執行,執行順序a>li>ul>div,有這樣一個機制,那麼我們給最外面的div加點選事件,那麼裡面的ul,li,a做點選事件的時候,都會冒泡到最外層的div上,所以都會觸發,這就是事件委託,委託它們父級代為執行事件。

4.如何實現

在介紹事件委託的方法之前,我們先來看一段一般方法的例子:

子節點實現相同的功能:

<ul id="ul1">
    <li>111</li>
    <li>222</li>
    <li>333</li>
    <li>444</li>
</ul>

實現功能是點選li,彈出123:

var oUl = document.getElementById("ul1");
    var aLi = oUl.getElementsByTagName('li');
    for(var i=0;i<aLi.length;i++){
        aLi[i].onclick = function(){
            alert(123);
        }
    }

上面的程式碼的意思很簡單,相信很多人都是這麼實現的,我們看看有多少次的dom操作,首先要找到ul,然後遍歷li,然後點選li的時候,又要找一次目標的li的位置,才能執行最後的操作,每次點選都要找一次li;
那麼我們用事件委託的方式做又會怎麼樣呢?(只執行一次DOM操作)

 var oUl = document.getElementById("ul1");
   oUl.onclick = function(){
        alert(123);
    }

這裡用父級ul做事件處理,當li被點選時,由於冒泡原理,事件就會冒泡到ul上,因為ul上有點選事件,所以事件就會觸發
當然,這裡當點選ul的時候,也是會觸發的,那麼問題就來了,如果我想只有點選li才會觸發,點選ul不觸發怎麼辦呢?
Event物件提供了一個屬性叫target,可以返回事件的目標節點,我們成為事件源,也就是說,target就可以表示為當前的事件操作的dom,但是不是真正操作dom,當然,這個是有相容性的,標準瀏覽器用e.target,IE瀏覽器用window.event.srcElement,此時只是獲取了當前節點的位置,並不知道是什麼節點名稱,這裡我們用nodeName來獲取具體是什麼標籤名,這個返回的是一個大寫的,我們需要轉成小寫再做比較(也可以直接比較大寫字母):

var oUl = document.getElementById("ul1");
  oUl.onclick = function(ev){
    var e = e || window.event;
    var target = e.target || e.srcElement;
    if(target.nodeName.toLowerCase() == 'li'){
            alert(123);
         alert(target.innerHTML);
    }
  }

這樣改下就只有點選li會觸發事件了,且每次只執行一次dom操作,如果li數量很多的話,將大大減少dom的操作,優化的效能可想而知!

1.概念

事件委託也叫事件代理,JavaScript高階程式設計上講:事件委託就是利用事件冒泡,只指定一個事件處理程式,就可以管理某一型別的所有事件。
用一個形象的例子說明:
有三個同事預計會在週一收到快遞。為簽收快遞,有兩種辦法:一是三個人在公司門口等快遞;二是委託給前臺MM代為簽收。現實當中,我們大都採用委託的方案(公司也不會容忍那麼多員工站在門口就為了等快遞)。前臺MM收到快遞後,她會判斷收件人是誰,然後按照收件人的要求籤收,甚至代為付款。這種方案還有一個優勢,那就是即使公司裡來了新員工(不管多少),前臺MM也會在收到寄給新員工的快遞後核實並代為簽收。

2.為什麼要用事件委託:

a.減少DOM操作,提高效能
b.讓新增的元素也繫結上事件
一般來說,dom需要有事件處理程式,我們都會直接給它設事件處理程式就好了,那如果是很多的dom需要新增事件處理呢?比如我們有100個li,每個li都有相同的click點選事件,可能我們會用for迴圈的方法,來遍歷所有的li,然後給它們新增事件,那這麼做會存在什麼影響呢?
在JavaScript中,新增到頁面上的事件處理程式數量將直接關係到頁面的整體執行效能,因為需要不斷的與dom節點進行互動,訪問dom的次數越多,引起瀏覽器重繪與重排的次數也就越多,就會延長整個頁面的互動就緒時間,這就是為什麼效能優化的主要思想之一就是減少DOM操作的原因;如果要用事件委託,就會將所有的操作放到js程式裡面,與dom的操作就只需要互動一次,這樣就能大大的減少與dom的互動次數,提高效能;
每個函式都是一個物件,是物件就會佔用記憶體,物件越多,記憶體佔用率就越大,自然效能就越差了(記憶體不夠用,是硬傷,哈哈),比如上面的100個li,就要佔用100個記憶體空間,如果是1000個,10000個呢,那隻能說呵呵了,如果用事件委託,那麼我們就可以只對它的父級(如果只有一個父級)這一個物件進行操作,這樣我們就需要一個記憶體空間就夠了,是不是省了很多,自然效能就會更好。

3.事件委託的原理:

事件委託是利用事件的冒泡原理來實現的,何為事件冒泡呢?就是事件從最深的節點開始,然後逐步向上傳播事件,舉個例子:頁面上有這麼一個節點樹,div>ul>li>a;比如給最裡面的a加一個click點選事件,那麼這個事件就會一層一層的往外執行,執行順序a>li>ul>div,有這樣一個機制,那麼我們給最外面的div加點選事件,那麼裡面的ul,li,a做點選事件的時候,都會冒泡到最外層的div上,所以都會觸發,這就是事件委託,委託它們父級代為執行事件。

4.如何實現

在介紹事件委託的方法之前,我們先來看一段一般方法的例子:

子節點實現相同的功能:

<ul id="ul1">
    <li>111</li>
    <li>222</li>
    <li>333</li>
    <li>444</li>
</ul>

實現功能是點選li,彈出123:

var oUl = document.getElementById("ul1");
    var aLi = oUl.getElementsByTagName('li');
    for(var i=0;i<aLi.length;i++){
        aLi[i].onclick = function(){
            alert(123);
        }
    }

上面的程式碼的意思很簡單,相信很多人都是這麼實現的,我們看看有多少次的dom操作,首先要找到ul,然後遍歷li,然後點選li的時候,又要找一次目標的li的位置,才能執行最後的操作,每次點選都要找一次li;
那麼我們用事件委託的方式做又會怎麼樣呢?會進行幾次DOM操作呢

 var oUl = document.getElementById("ul1");
   oUl.onclick = function(){
        alert(123);
    }

這裡用父級ul做事件處理,當li被點選時,由於冒泡原理,事件就會冒泡到ul上,因為ul上有點選事件,所以事件就會觸發
當然,這裡當點選ul的時候,也是會觸發的,那麼問題就來了,如果我想只有點選li才會觸發,點選ul不觸發怎麼辦呢?
Event物件提供了一個屬性叫target,可以返回事件的目標節點,我們成為事件源,也就是說,target就可以表示為當前的事件操作的dom,但是不是真正操作dom,當然,這個是有相容性的,標準瀏覽器用e.target,IE瀏覽器用window.event.srcElement,此時只是獲取了當前節點的位置,並不知道是什麼節點名稱,這裡我們用nodeName來獲取具體是什麼標籤名,這個返回的是一個大寫的,我們需要轉成小寫再做比較(也可以直接比較大寫字母):

var oUl = document.getElementById("ul1");
  oUl.onclick = function(ev){
    var e = e || window.event;
    var target = e.target || e.srcElement;
    if(target.nodeName.toLowerCase() == 'li'){
            alert(123);
         alert(target.innerHTML);
    }
  }

這樣改下就只有點選li會觸發事件了,且每次只執行一次dom操作,如果li數量很多的話,將大大減少dom的操作,優化的效能可想而知!

(2)上面講的都是document載入完成的現有dom節點下的操作,那麼如果是新增的節點,新增的節點會有事件嗎?也就是說,一個新員工來了,他能收到快遞嗎?

看一下正常的新增節點的方法

 <button id="btn">按鈕</button>
    <ul id="ul1">
        <li>111</li>
        <li>222</li>
    </ul>
    <script>
        var oBtn = document.getElementById("btn");
        var oUl1 = document.getElementById("ul1");
        var aLi = document.getElementsByTagName("li");
        oBtn.onclick = function(){
            var oLi = document.createElement("li");
            oLi.innerHTML = Math.random();
            oUl1.appendChild(oLi);
        }
        for(var i =0;i<aLi.length;i++){
            aLi[i].onclick = function(){
                alert(this.innerHTML);
            }
        }

這是一般的做法,但是你會發現,新增的li是沒有事件的,說明新增子節點的時候,事件沒有一起新增進去,這不是我們想要的結果,這時候事件委託就要上場了

 var oBtn = document.getElementById("btn");
        var oUl1 = document.getElementById("ul1");
        var aLi = document.getElementsByTagName("li");
        oBtn.onclick = function(){
            var oLi = document.createElement("li");
            oLi.innerHTML = Math.random();
            oUl1.appendChild(oLi);
        }
        oUl1.onclick = function(e){
            e = e || window.event;
            var target = e.target || e.srcElement;
            if(target.tagName =="LI"){
                alert(target.innerHTML);
            }
        }

看,上面是用事件委託的方式,新新增的子元素是帶有事件效果的,我們可以發現,當用事件委託的時候,根本就不需要去遍歷元素的子節點,只需要給父級元素新增事件就好了,其他的都是在js裡面的執行,這樣可以大大的減少dom操作,這才是事件委託的精髓所在。

5.總結:

那什麼樣的事件可以用事件委託,什麼樣的事件不可以用呢?

適合用事件委託的事件:click,mousedown,mouseup,keydown,keyup,keypress。

值得注意的是,mouseover和mouseout雖然也有事件冒泡,但是處理它們的時候需要特別的注意,因為需要經常計算它們的位置,處理起來不太容易。

不適合的就有很多了,舉個例子,mousemove,每次都要計算它的位置,非常不好把控,在不如說focus,blur之類的,本身就沒用冒泡的特性,自然就不能用事件委託了。

相關推薦

前端系統複習事件委託

1.概念 事件委託也叫事件代理,JavaScript高階程式設計上講:事件委託就是利用事件冒泡,只指定一個事件處理程式,就可以管理某一型別的所有事件。 用一個形象的例子說明: 有三個同事預計會在週一收到快遞。為簽收快遞,有兩種辦法:一是三個人在公司門口等快

前端系統複習瀏覽器渲染機制

二面的內容: 渲染機制 JS 執行機制 頁面效能 錯誤監控 本文接下來講渲染機制。 渲染機制包括的內容: 什麼是DOCTYPE及作用 瀏覽器渲染過程 面試經常會問:在瀏覽器中輸入url,發生了哪些事情。其中有一部就是瀏覽器的渲染過程。

JS學習事件委託

在學習事件委託時一直是迷茫的,今天看到@凌雲之翼的部落格文,受益匪淺,轉載過來以備記錄,留著學習用,謝謝老師~~~ 概述: 那什麼叫事件委託呢?它還有一個名字叫事件代理,JavaScript高階程式設計上講:事件委託就是利用事件冒泡,只指定一個事件處理程式,就可以管理某一型別的所有事件。那這是什麼意思呢?網上

高效能 javaScript 事件委託(Vue版)

一、概念理解: 1、事件:HTML DOM 使 JavaScript 有能力對 HTML 事件做出反應。比如點選事件、滑鼠移入/移出事件等。事件通常與函式配合使用,這樣就可以通過發生的事件來驅動函式執行。 2、DOM 事件流:冒泡事件流、捕獲事件流。 3、

js事件事件冒泡的應用----事件委託

什麼是事件委託? 它還有一個名字叫事件代理。 JavaScript高階程式設計上講: 事件委託就是利用事件冒泡,只指定一個事件處理程式,就可以管理某一型別的所有事件。 用取快遞來解釋這個現象,大家認真領會一下事件委託到底是一個什麼原理: 有三個同事預計會在週一收到快遞。為簽收快遞,有兩種辦法:一

jQuery事件和批量操作、事件委託示例

一、常用事件 click(function(){...}) // 點選時觸發 focus(function(){...}) // 獲得焦點觸發 blur(function(){...}) // 失去焦點觸發 change(function(){...}) // 內容改變後觸發

UnityC#——委託事件,觀察者模式,貓和老鼠事例

委託與事件,觀察者模式,貓和老鼠事例     在Unity遊戲開發中,我們經常需要在一個類中,呼叫另一個類中的方法,比如,當玩家進入到某個地方,敵人就開始攻擊玩家。這時就需要利用委託與事件,設計觀察者模式。 此處我們利用貓和老鼠來簡單描述: 程式碼如下: Ca

JS捕獲冒泡和事件委託

一、事件流(捕獲,冒泡)   事件流:指從頁面中接收事件的順序,有冒泡流和捕獲流。 當頁面中發生某種事件(比如滑鼠點選,滑鼠滑過等)時,毫無疑問子元素和父元素都會接收到該事件,可具體順序是怎樣的呢?冒泡和捕獲則描述了兩種不同的順序。   DOM2

React原始碼分析事件系統

React原始碼分析之事件系統(轉載自阿里雲) react自己實現了一套高效的事件系統,包括了事件的註冊、儲存、分發、和重用,在DOM事件體系基礎上做了很大改進,減少了記憶體消耗,簡化了事件邏輯,並最大化的解決了IE等瀏覽器的事件不相容問題。與傳統的DOM體系相比,它有如下特點:

中高階前端應該必會,js實現事件委託代理、切換樣式、元素獲取相對於文件位置等

1、介紹   隨著元件開發大流行,現在三大框架已經基本佔領了整個前端。   這時候,我們要是引入一個 jq 是不是先得你的專案非常臃腫,jq 也很不適合。   這個時候,你就需要來增加你 js 的功底。 2、各種操作   1、事件委託   案例分析: <ul id= "list

複習JavaScript基本語法(一)——三種引入方式及load、write事件

JavaScript是什麼 JavaScript一種直譯式指令碼語言,是一種動態型別、弱型別、基於原型的語言,內建支援型別。它的直譯器被稱為JavaScript引擎,為瀏覽器的一部分,廣泛用於客戶端的指令碼語言。 JavaScript的作用 JavaScript

複習JavaScript基本語法(六)——事件監聽總彙

事件監聽 簡單事件監聽 btn.onclick 點選事件 <div class="box" id="box"> <H1> 測試模組</H1> <H1> 測試模組</H1> <

前端事件委託詳解

起因: 1、這是前端面試的經典題型,要去找工作的小夥伴看看還是有幫助的; 2、其實我一直都沒弄明白,寫這個一是為了備忘,二是給其他的知其然不知其所以然的小夥伴們以參考; 概述: 那什麼叫事件委託呢?它還有一個名字叫事件代理,JavaScript高階程式設計上講:事

軟考複習計算機組成原理儲存系統

儲存裝置 my knowledge: 儲存有記憶體 外存之分 記憶體:儲存速度快,儲存空間小,易丟失,外存:儲存空間大,不易丟失,訪問速度慢,一般是磁碟,然後暫存器和記憶體不是一個東西,暫存器在cpu裡,大概就是這麼多了。  軟考書籍知識: 軟考試題知識點:

大白話系列C#委託事件講解(一)

從序言中,大家應該對委託和事件的重要性有點了解了吧,雖然說我們現在還是能模糊,但是從我的大白話系列中,我會把這些概念說的通俗易懂的。首先,我們還是先說說委託吧,從字面上理解,只要是中國人應該都知道這個意思,除非委託2箇中文字不認識,舉個例子,小明委託小張去買車票。    &nbs

大白話系列C#委託事件講解大結局

今天是大白話系列之C#委託與事件講解的大結局,也是我們最關心的,在日常的MES系統程式設計中到底怎樣使用這樣的利器,其實我們每天都在使用事件,一個窗體,一個按鈕都包含這事件,只是很少用到自己寫的委託和事件,說白了不知道如何下手,也不知道在什麼樣的場景下應用。 用到事件的地方有很多,這次講解就ME

大白話系列C#委託事件講解(二)

什麼是事件?EVENT?點選事件?載入事件?一連串的模糊的概念衝擊著我們弱小的腦袋 那我們首先來看一下比較正統的感念吧: 事件是類在發生其關注的事情時用來提供通知的一種方式。 事件的發生一般都牽扯2個角色 事件發行者(Publisher):一個事件的發行者,也稱作是傳送者(sende

計算機系統結構重要知識點複習

                          

JavaScript 預設行為 DOM2級,事件委託機制

1. 事件預設行為及阻止方式    1.1 瀏覽器的預設行為       JavaScript事件本身所具有的屬性,例如a標籤的跳轉,Submit按鈕的提交,右鍵選單,文字框的輸入等。    1.2 阻止預設行為的方式

(001)資料庫系統工程師軟考複習計算機系統基礎知識

運算器(ALU)分為:算術運算、邏輯運算 加法器:儲存運算元和運算結果 程式狀態暫存器:執行結果的狀態儲存 控制器:分析和執行指令 指令暫存器:儲存執行的指令 指令譯碼器:分析操作做什麼(加或減等) 程式計數器:順序執行,儲存下一條執行的指令的地址,並不斷向後移動一個