JavaScript事件委託機制與this的比較

很多時候我們在完成交互時,頁面的一些dom結構是根據後臺傳輸過來的數據動態加載的,如果說我們需要給這些數量比較大的dom結構(比如說表格,或則ul>li)添加click或則hover事件時,手寫/遍歷生成元素內的onclick函數式不可取的,會大量的消耗瀏覽器內存,降低程序的性能。所以,採用事件委託機制或this就來替代就顯得很有必要了。

一.什麼是事件委託機制

簡單來說,就是藉助event事件對象和事件觸發的冒泡流程來完成事件委託機制。冒泡流程顧名思義,當你點擊某個元素時,事件捕捉會從它的父級往上查找,一直到domcument爲止。而event事件對象則是委託機制的重點所在,藉助它,我們可以做到定點觸發,指哪打哪。
舉個例子:

<button id="addBtn">添加</button>
<ul id="owenUl">
    <li>111</li>
    <li>222</li>
    <li>333</li>
</ul>

我們想給ul中的不同的li的添加點擊事件,普通寫法如下:

var $li = $('#owenUl').children();
var len = $li.length;
for(var i =0; i<= len-1;i++){
   $($li[i]).on('click',function () { 
      alert(this.innerHTML)
   }) 
}

此思路想必大家都經歷過:先獲取父級元素的所有子元素,然後在遍歷子元素時添加點擊事件。它的缺點我不再多說。

下面是事件委託寫法:

$('#owenUl').on('click',function(event){
    //獲取event和target兼容ie的寫法
    var ev = event || window.event;
  var target = ev.target || ev.srcElement;
  //獲取點擊節點的元素類型名
    if(target.nodeName.toLowerCase() == "li"){
      //此時的target就是<li>dom元素
      alert(target.innerHTML)
    }
})$('#addBtn').on('click',function () {
   var str = '<li>123456</li>';
   $('#owenUl').append(str);
})

對於已存在的dom結構事件委託可以正常添加事件,那麼對於用戶操作後增加的dom呢?答案是也可以。
這裏寫圖片描述

二.事件委託與this的比較

關於javascript的this,在什麼情況下指向什麼,嚴格模式和非嚴格模式的下this的區別在哪,還有this可以通過哪些函數改變指向,以及在箭頭函數中this的指向等等這一系列問題,在本篇中暫不概述,有興趣的話可以點擊下面的鏈接看看我寫的另一篇關於tihs指向問題的探究:
javascript this探究

我們在本篇中只談談用this改寫的事件綁定與事件委託改寫的事件綁定有何區別:
假如有以下dom結構:

<button id="addBtn">添加</button>
<ul id="owenUl">
    <li>111</li>
    <li>222</li>
    <li>333</li>
</ul>

我們進行以下改寫:

$('#owenUl li').on('click', function () {
       alert(this.innerHTML);
 })

相比較,是不是比事件委託代碼量還少?邏輯還簡單?事件委託能起到的效果,它一樣可以,在一些相對較複雜的業務需求下,它能使的代碼複雜度更低:
假如我們有以下dom結構:

 <button id="addBtn">添加</button>
    <ul id="owenUl">
        <li>
            <span>1111</span>
        </li>
        <li>
            <span>2222</span>
        </li>
        <li>
            <span>3333</span>
        </li>
    </ul>

整個dom的css如下:

ul li {
        width: 49px;
        height: 30px;
        border: 1px solid gray;
        margin-bottom: 10px;
      }

實際效果如圖:
這裏寫圖片描述

現在我們有以下業務需求:
1.點擊li裏的區域時,要能顯示span的內容。
2.點擊不同的li顯示各自span的內容。

如果是使用事件委託,我們可以這麼寫:

$('#owenUl').on('click', function (event) {
    //獲取event和target兼容ie的寫法
    var ev = event || window.event;
    var target = ev.target || ev.srcElement;
    var text;
    switch (target.nodeName.toLowerCase()) {
        case "li":
           var spanDom = target.children[0];
           text = spanDom.innerHTML;
           console.log('li')
           break;
        case "span":
           text = target.innerHTML;
           console.log('span')
           break;
        default:
           break;
        }
        console.log(text)
})

事件委託的機制的問題在於,當你在判斷target.nodeName.toLowerCase() == 'li'的邏輯裏去做業務時,你點擊li中的span元素是得不到任務反應的,也就是說在此判斷中,點擊裏面的span時,console.log('li')這一塊的代碼並不會被觸發,因此代碼的複雜度就高了。
  下面我們看用this來改寫是什麼樣子:

$('#owenUl li').on('click', function (event) {
    var spanDom = this.children[0]
    console.log(spanDom.innerHTML);
})

很驚訝對吧,就兩行代碼。只要你在寫代碼前捋清了業務邏輯。用this改寫代碼的複雜度大大降低,也減少了維護成本。

綜上,我個人是比較喜歡用this來進行事件綁定的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章