1. 程式人生 > >javascript事件委託和jquery事件委託

javascript事件委託和jquery事件委託

元旦過後,新年第一篇。
初衷:很多的面試都會涉及到事件委託,前前後後也看過好多博文,寫的都很不錯,寫的各有千秋,自己思前想後,為了以後自己的檢視,也同時為現在找工作的前端小夥伴提供一個看似更全方位的解讀事件委託的地方來認識瞭解他的原理,本篇文章彙總了兩個版本的事件委託:javascript、jquery;

事件委託的定義:

利用事件冒泡,指定一個事件處理程式,就可以管理某一型別的所有事件。

事件委託的優勢:

  • 在js中新增到頁面上的事件處理程式的個數直接影響到網頁的執行效能。因為每個事件處理函式都是一個物件,是物件就會佔用記憶體,而記憶體中物件越多,導致的結果就是效能越差;而訪問dom的次數越多,就會引起結構的重繪或者重排的次數也隨之增多,會延遲整個頁面的互動就緒時間;
  • 對於在頁面進行處理過後新增的dom元素,運用事件委託可以為新增的dom元素一併增減事件處理程式;

    在下面的程式碼中p標籤要實現的效果是滑鼠點選p標籤的時候背景色變為紅色,以下是js、jq的處理方法

<body>
    <div id="nodes">
      <P class="node_p">第一個p</P>
      <P class="node_p">第二個p</P>
      <P class="node_p">第三個p</P>
      <div id="childDiv">
          <p>這是子集選單</p>
          <div>我是子集的div
              <p>我是子集的p</p>
          </div>
      </div>
    </div>
    <button>點選加一</button>
  </body>

一、js事件委託

在js中不用事件委託的情況:獲取頁面中所有的p標籤然後用for迴圈遍歷給每一個元素增加事件處理函式

let nodes = document.getElementById("nodes");
    let ps = document.getElementsByTagName("p");
    console.log(ps);
    let btn = document.getElementsByTagName("button")[0];
    let inner = 33;

    btn.onclick = function() {
      inner++;
      let p = document.createElement("p");
      p.innerHTML = inner + "新增的p標籤啊";
      nodes.appendChild(p);
      console.log(ps);
    };
    for (let i= 0;i<ps.length;i++){
        ps[i].onclick= function(){
            this.style.background = 'red'
        }  
    }

這時候在瀏覽器中執行之後進行測試,發現如圖一所示的結果;
圖一
那麼js不用事件委託怎麼給新增加的標籤新增事件處理函式呢?解決方案如下:

let nodes = document.getElementById("nodes");
    let ps = document.getElementsByTagName("p");
    console.log(ps);
    let btn = document.getElementsByTagName("button")[0];
    let inner = 33;

    btn.onclick = function () {
        inner++;
        let p = document.createElement("p");
        p.innerHTML = inner + "新增的p標籤啊";
        nodes.appendChild(p);
        addEvent();//將新dom元素增加到頁面後再執行迴圈函式
        console.log(ps);
    };

    function addEvent() {
        for (let i = 0; i < ps.length; i++) {
            ps[i].onclick = function () {
                this.style.background = 'red'
            }
        }
    }
    addEvent() //先執行一遍迴圈

這時候瀏覽器中執行如圖二所示:
圖二
這時候雖然解決了為新增dom元素增加事件處理函式的問題,但是仔細考慮他的效能卻是比之前都有所下降,究其原因就是又增加了一個事件處理函式(物件),又一次佔用了記憶體;所以,這個時候就會用但事件委託,這時候事件委託的優勢也有所體現出來:

let nodes = document.getElementById("nodes");
    let ps = document.getElementsByTagName("p");
    console.log(ps);
    let btn = document.getElementsByTagName("button")[0];
    let inner = 33;

    btn.onclick = function () {
        inner++;
        let p = document.createElement("p");
        p.innerHTML = inner + "新增的p標籤啊";
        nodes.appendChild(p);
        console.log(ps);
    };
//事件委託,為nodes指定一個事件處理函式,處理nodes下為p標籤的所有元素的cilck事件
    nodes.onclick= function(e){
        let ev = e || window.event
        let target = ev.target || ev.srcElement //srcElement IE瀏覽器
        //這裡要判被處理元素節點的名字,也可以增加相應的判斷條件 target.nodeName.toLowerCase() == 'p'||target.nodeName.toLowerCase() == 'span',但是要注意不要使用父級元素的名稱,因為再點選子元素之間的空氣的時候,由於事件冒泡他會給父級元素也增加相應的事件處理函式;因為返回的節點名稱一般都是大寫,所以這時要用toLowerCase()處理一下;
        if(target.nodeName.toLowerCase() == 'p'){ 
            target.style.background = 'green'
        }
    }

這時候瀏覽器中執行的結果如圖三所示:
圖三

二、jquery事件委託:

相較於js事件委託,jquery事件委託的優勢:執行事件委託的時候只有子元素會觸發事件函式,而代為執行的父元素不會觸發時間函式,因此不用去判斷元素節點的名稱;
這裡nodes節點下所有標籤為p的子節點都被賦予事件處理函式;這裡的子節點還可以是多個類似' p,span',需要注意這裡面也不可以寫同nodes一樣的標籤,否則點選元素之間的間隔會給nodes下的div賦予事件處理函式;如例二:
例一:

let inner = 33;
//這裡nodes節點下所有標籤為p的子節點都被賦予事件處理函式;這裡的子節點還可以是多個類似' p,span',需要注意這裡面也不可以寫同nodes一樣的標籤,否則點選元素之間的間隔會給nodes下的div賦予事件處理函式
$('#nodes').on('click','p',function(e){
        let target = $(e.target)
        target.css('backgroundColor','red')
    })
    $('button').click(()=>{
        inner++;
        $('#nodes').append($('<p>我是新增加的p標籤'+inner+'</p>'))
    })

瀏覽器執行的效果如圖四所示:
圖四
例二:

<body>
    <div id="nodes">
        <P class="node_p">第一個p</P>
        <P class="node_p">第二個p</P>
        <P class="node_p">第三個p</P>
        <span class="node_p">span</span>
        <div id="childDiv">
            <p>這是子集選單</p>
            <div>我是子集的div
                <p>我是子集的p</p>
            </div>
        </div>
    </div>
    <button>點選加一</button>
</body>
<script>
let inner =33;
$('#nodes').on('click','p,div,span',function(e){
        let target = $(e.target)
        target.css('backgroundColor','red')
    })
    $('button').click(()=>{
        inner++;
        $('#nodes').append($('<p>我是新增加的p標籤'+inner+'</p>'))
    })
</script>

瀏覽器執行效果如圖五所示:
圖五

事件委託不僅僅只是為處理一種dom操作型別,他可以進行增刪改查等功能:

js事件委託:不同操作

<body>
    <div id="events">
        <input type="button" id='addHandle' value='增加'>
        <input type="button" id='deleteHandle' value='減少'>
    </div>
    <div id="content">

    </div>
</body>
<script src='http://code.jquery.com/jquery-2.1.1.min.js'></script>
<script>
    let events = document.getElementById('events');
    let content = document.getElementById('content');
    events.onclick=function(e){
        let ev = e || window.event;
        let target = ev.target || ev.srcElement;
        if(target.nodeName.toLowerCase()=='input'){
            switch(target.id){
                case 'addHandle':
                return addEvent();
                break
                case 'deleteHandle':
                return deleteEvent();
                break
            }
        }
    }
    function addEvent(){
        let add = document.createElement('p')
        add.innerHTML = '這是增加按鈕'
        content.appendChild(add)
    }
    function deleteEvent(){
        let del = document.createElement('p')
        del.innerHTML = '這是刪除按鈕'
        content.appendChild(del)
    }
</script>

瀏覽器中的效果如圖六所示:
圖六

jquery事件委託:不同操作

$('#events').on('click','input',(e)=>{
        let target = $(e.target);
        switch(target[0].id){
                case 'addHandle':
                return addEvent();
                break
                case 'deleteHandle':
                return deleteEvent();
                break
        }
    })
    function addEvent(){
        $('#content').append($('<div>這是增加按鈕</div>'))
    }
    function deleteEvent(){
        $('#content').append($('<div>這是刪除按鈕</div>'))
    }

瀏覽器中的效果如圖七所示:
圖七

本文如有不實之處,還望大神指點一二,歡迎討論!

2019我在路上,加油!