成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

JavaScript事件委托原理

lscho / 1804人閱讀

摘要:概念事件委托,通俗來(lái)說(shuō)就是將元素的事件委托給它的父級(jí)或者更外級(jí)元素處理。級(jí)事件規(guī)定的事件流包括三個(gè)階段事件捕獲目標(biāo)階段事件冒泡原理事件委托就是利用事件冒泡機(jī)制實(shí)現(xiàn)的。最適合采用事件委托技術(shù)的事件包括和。

概念

事件委托,通俗來(lái)說(shuō)就是將元素的事件委托給它的父級(jí)或者更外級(jí)元素處理。

事件流
事件流描述的是從頁(yè)面中接收事件的順序。

事件冒泡:事件開(kāi)始由最具體的元素接收,然后逐級(jí)向上傳播到較為不具體的節(jié)點(diǎn)(或文檔)。

事件捕獲:事件開(kāi)始由不太具體的節(jié)點(diǎn)接收,然后逐級(jí)向下傳播到最具體的節(jié)點(diǎn)。它與事件冒泡是個(gè)相反的過(guò)程。

DOM2級(jí)事件規(guī)定的事件流包括三個(gè)階段:

事件捕獲

目標(biāo)階段

事件冒泡

原理
事件委托就是利用事件冒泡機(jī)制實(shí)現(xiàn)的。

假設(shè)有一個(gè)列表,要求點(diǎn)擊列表項(xiàng)彈出對(duì)應(yīng)字段。

不使用事件委托

var myLink = document.getElementById("myLink");
var li = myLink.getElementsByTagName("li");

for(var i = 0; i < li.length; i++) {
  li[i].onclick = function(e) {
    var e = event || window.event;
    var target = e.target || e.srcElement;
    alert(e.target.id + ":" + e.target.innerText);  
  };
}

這樣做存在的問(wèn)題:

給每個(gè)列表項(xiàng)都綁定事件,消耗內(nèi)存

當(dāng)有動(dòng)態(tài)添加的元素時(shí),需要重新給元素綁定事件

使用事件委托

var myLink = document.getElementById("myLink");

myLink.onclick = function(e) {
  var e = event || window.event;
  var target = e.target || e.srcElement;
  if(e.target.nodeName.toLowerCase() == "li") {
    alert(e.target.id + ":" + e.target.innerText);
  }
};

上述代碼是將事件委托給列表項(xiàng)的父級(jí),通過(guò) target 下的 nodeName 屬性作出判斷。

也可以給每個(gè)列表項(xiàng)綁定與其對(duì)應(yīng)的事件。如:

var myLink = document.getElementById("myLink");

myLink.onclick = function(e) {
  var e = event || window.event;
  var target = e.target || e.srcElement;
  switch(target.id) {
    case "1":
      target.style.backgroundColor = "red";
      break;
    case "2":
      alert("這是第二項(xiàng)");
      break;
    case "3":
      alert(e.target.id + ":" + e.target.innerText);
      break;
    default:
      alert("...");
  }
};

上述代碼是通過(guò)判斷 target 下的 id 屬性,執(zhí)行不同的事件。

事件委托的優(yōu)點(diǎn):

只需要將同類(lèi)元素的事件委托給父級(jí)或者更外級(jí)的元素,不需要給所有元素都綁定事件,減少內(nèi)存空間占用,提升性能

動(dòng)態(tài)新增的元素?zé)o需重新綁定事件

需要注意的地方:

事件委托的實(shí)現(xiàn)依靠事件冒泡,因此不支持事件冒泡的事件就不適合用事件委托。

最適合采用事件委托技術(shù)的事件包括 clickmousedown、mouseup、keydownkeyupkeypress。雖然 mouseovermouseout 事件也冒泡,但要適當(dāng)處理它們并不容易,而且經(jīng)常需要計(jì)算元素的位置。(因?yàn)楫?dāng)鼠標(biāo)從一個(gè)元素移到其子節(jié)點(diǎn)時(shí),或者當(dāng)鼠標(biāo)移出該元素時(shí),都會(huì)觸發(fā) mouseout 事件。)

不是所有的事件綁定都適合使用事件委托,不恰當(dāng)使用反而可能會(huì)導(dǎo)致不需要綁定事件的元素也被綁定上了事件。

Jquery中的事件委托

jquery中實(shí)現(xiàn)事件委托的幾種方法:

on

on(events, [selector], [data], fn)
// 將 li 的事件委托給它的父元素
$("#myLink").on("click", "li", function() {
    // todo...
});

live

該方法在 jquery 1.7 版本已被廢棄。

delegate

delegate(selector, [type], [data], fn)
$("#myLink").delegate("li", "click", function() {
    // todo...
});

該方法在 jquery 3.0 版本已被廢棄。用 on() 代替。

jquery 中, delegate() 、live() 、 one()bind()等最終都是依賴(lài) on() 方法實(shí)現(xiàn)的。因此可以直接使用 on() 替代其他方法。

封裝一個(gè)事件委托方法

需要注意的地方:

保證兼容性,包括:事件綁定、元素選擇器 Element.matches 、事件 event 對(duì)象

回調(diào)函數(shù) this 指向

上面的示例中,當(dāng)目標(biāo)元素下還有子元素時(shí),子元素不能觸發(fā)事件。解決辦法是在觸發(fā)過(guò)程中對(duì)元素進(jìn)行判斷,如果當(dāng)前觸發(fā)的元素不是目標(biāo)元素,就繼續(xù)往該元素的 parentNode 查找,否則循環(huán)結(jié)束。

/**
 * [delegateEvent description]
 * @param  {[type]}   parentSelector 父元素
 * @param  {[type]}   targetSelector 目標(biāo)元素
 * @param  {[type]}   events         事件
 * @param  {Function} fn             回調(diào)函數(shù)
 * @return {[type]}                  null
 */
function delegateEvent(parentSelector, targetSelector, events, fn) {
            
  // 事件綁定兼容性處理
  function addEvent(ele, type, handle) {
    if(ele.addEventListener) {
      ele.addEventListener(type, handle, false);
    } else if(ele.attachEvent){
      ele.attachEvent("on" + type, handle);
    } else {
      ele["on" + type] = handle;
    }
  }

  // 如果元素被指定的選擇器字符串選擇,Element.matches()  方法返回 true; 否則返回 false。
  // 對(duì)于不支持 Element.matches() 或 Element.matchesSelector(),但支持 document.querySelectorAll() 方法的瀏覽器,存在以下替代方案
  if (!Element.prototype.matches) {
    Element.prototype.matches = 
    Element.prototype.matchesSelector || 
    Element.prototype.mozMatchesSelector ||
    Element.prototype.msMatchesSelector || 
    Element.prototype.oMatchesSelector || 
    Element.prototype.webkitMatchesSelector ||
    function(s) {
      var matches = (this.document || this.ownerDocument).querySelectorAll(s),
        i = matches.length;
      while (--i >= 0 && matches.item(i) !== this) {}
        return i > -1;            
      };
    }

    // 事件處理邏輯
    addEvent(parentSelector, events, function(e) {
              
      // 兼容性處理
      var e = e || window.event;
      var t = e.target || e.srcElement;
      
      // currentTarget === parentSelector           
      var currentTarget = e.currentTarget;

      // 遍歷并判斷是否為目標(biāo)元素,如果不是,則往元素的 parentNode 繼續(xù)查找
      while(!t.matches(targetSelector)) {
        // 如果是目標(biāo)元素則跳出循環(huán)
        if(t === currentTarget) {
          t = null;
          break;
        }
        t = t.parentNode;
      }

      if(t) {
        // 將回調(diào)函數(shù)的 this 指向目標(biāo)元素
        fn.call(t, Array.prototype.slice.call(arguments));
      }
    });

}

調(diào)用示例:

var myLink = document.querySelector("#myLink");

delegateEvent(myLink, "li.link", "click", function() {
  console.log(this, this.id + ":" + this.innerText);
});

原文地址:https://github.com/daijingfeng/blog/issues/1

參考資料:

1、《JavaScript高級(jí)程序設(shè)計(jì)(第3版)》

2、Element.matches() API https://developer.mozilla.org...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/90226.html

相關(guān)文章

  • 好文推薦:javascript: 事件委托解析

    摘要:前言之前不太明白事件委托??戳诉@個(gè)帖子,跟著代碼操作了一遍,終于明白了事件委托。推薦理由一步一步,漸進(jìn)式分析來(lái)說(shuō)明事件委托。為簽收快遞,有兩種辦法一是三個(gè)人在公司門(mén)口等快遞二是委托給前臺(tái)代為簽收。 前言:之前不太明白事件委托。 看了這個(gè)帖子,跟著代碼操作了一遍,終于明白了事件委托。所以轉(zhuǎn)載。 推薦理由:一步一步,漸進(jìn)式分析來(lái)說(shuō)明事件委托。 什么叫事件委托呢?它還有一個(gè)名字叫事件代理 ...

    Wuv1Up 評(píng)論0 收藏0
  • 我所理解的JavaScript 事件委托

    摘要:當(dāng)初學(xué)時(shí),學(xué)到委托概念的時(shí)候,有點(diǎn)不知所措,在工作后運(yùn)用了很多后才發(fā)現(xiàn)真的好用。事件的冒泡,所以才可以在父元素來(lái)監(jiān)聽(tīng)子元素觸發(fā)的事件。事件的冒泡這個(gè)要講一下,在的時(shí)候我們可以設(shè)置事件模型事件冒泡事件捕獲,一般來(lái)說(shuō)都是用事件冒泡的模型。 當(dāng)初學(xué)C#時(shí),學(xué)到委托概念的時(shí)候,有點(diǎn)不知所措,在工作后運(yùn)用了很多后才發(fā)現(xiàn)真的好用。在JavaScript里面也有事件委托的概念,那在JavaScrip...

    vvpvvp 評(píng)論0 收藏0
  • 我所理解的JavaScript 事件委托

    摘要:當(dāng)初學(xué)時(shí),學(xué)到委托概念的時(shí)候,有點(diǎn)不知所措,在工作后運(yùn)用了很多后才發(fā)現(xiàn)真的好用。事件的冒泡,所以才可以在父元素來(lái)監(jiān)聽(tīng)子元素觸發(fā)的事件。事件的冒泡這個(gè)要講一下,在的時(shí)候我們可以設(shè)置事件模型事件冒泡事件捕獲,一般來(lái)說(shuō)都是用事件冒泡的模型。 當(dāng)初學(xué)C#時(shí),學(xué)到委托概念的時(shí)候,有點(diǎn)不知所措,在工作后運(yùn)用了很多后才發(fā)現(xiàn)真的好用。在JavaScript里面也有事件委托的概念,那在JavaScrip...

    wushuiyong 評(píng)論0 收藏0
  • 簡(jiǎn)單說(shuō) JavaScript中的事件委托(上)

    摘要:說(shuō)明這篇文章說(shuō)中的事件委托,這次先說(shuō)一些比較基本的知識(shí)。第一段綁定了兩次事件,第二段綁定了一次事件也就是說(shuō),原來(lái)在上綁定的事件,現(xiàn)在委托在了父元素上,而在上只需要綁定一次就可以了。我們用事件委托的方式,再來(lái)改改。 說(shuō)明 這篇文章說(shuō)JavaScript中的事件委托,這次先說(shuō)一些比較基本的知識(shí)。 事件委托 是什么 先來(lái)看看事件委托的概念 事件委托就是利用事件冒泡,只指定一個(gè)事件處理程序,就...

    fireflow 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<