久久99久久人婷婷精品综合_超碰aⅴ人人做人人爽欧美_亚洲电影第三页_日韩欧美一中文字暮专区_波多野结衣的一区二区三区_婷婷在线播放_人人视频精品_国产精品日韩精品欧美精品_亚洲免费黄色_欧美性猛交xxxxxxxx

好程序員分享JavaScript事件委托代理和函數封裝詳解-創新互聯

好程序員 分享 JavaScript 事件委托代理和函數封裝詳解 , JavaScript 高級程序設計上講:事件委托就是利用事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件。下面我們一起看看事件代理相關介紹。

創新互聯堅持“要么做到,要么別承諾”的工作理念,服務領域包括:成都網站設計、成都網站建設、企業官網、英文網站、手機端網站、網站推廣等服務,滿足客戶于互聯網時代的龍子湖網站設計、移動媒體設計的需求,幫助企業找到有效的互聯網解決方案。努力成為您成熟可靠的網絡建設合作伙伴!

 

當用事件委托的時候,根本就不需要去遍歷元素的子節點,只需要給父級元素添加事件就好了,其他的都是在 js 里面的執行,這樣可以大大的減少 dom 操作,這才是事件委托的精髓所在。

 

基本概念

 

事件委托,通俗地來講,就是把一個元素響應事件( click 、 keydown...... )的函數委托到另一個元素;

 

一般來講,會把一個或者一組元素的事件委托到它的父層或者更外層元素上,真正綁定事件的是外層元素,當事件響應到需要綁定的元素上時,會通過事件冒泡機制從而觸發它的外層元素的綁定事件上,然后在外層元素上去執行函數。

 

舉個例子,比如一個宿舍的同學同時快遞到了,一種方法就是他們都傻傻地一個個去領取,還有一種方法就是把這件事情委托給宿舍長,讓一個人出去拿好所有快遞,然后再根據收件人一一分發給每個宿舍同學;

 

在這里,取快遞就是一個事件,每個同學指的是需要響應事件的 DOM 元素,而出去統一領取快遞的宿舍長就是代理的元素,所以真正綁定事件的是這個元素,按照收件人分發快遞的過程就是在事件執行中,需要判斷當前響應的事件應該匹配到被代理元素中的哪一個或者哪幾個。

 

事件冒泡

 

前面提到 DOM 中事件委托的實現是利用事件冒泡的機制,那么事件冒泡是什么呢?

 

在 document.addEventListener 的時候我們可以設置事件模型:事件冒泡、事件捕獲,一般來說都是用事件冒泡的模型;

好程序員分享JavaScript事件委托代理和函數封裝詳解

如上圖所示,事件模型是指分為三個階段:

 

捕獲階段:在事件冒泡的模型中,捕獲階段不會響應任何事件;

目標階段:目標階段就是指事件響應到觸發事件的最底層元素上;

冒泡階段:冒泡階段就是事件的觸發響應會從最底層目標一層層地向外到最外層(根節點),事件代理即是利用事件冒泡的機制把里層所需要響應的事件綁定到外層; ### 事件

 

 

委托的優點

 

1. 減少內存消耗

 

試想一下,若果我們有一個列表,列表之中有大量的列表項,我們需要在點擊列表項的時候響應一個事件;

 

<ul id="list">

  <li>item 1</li>

  <li>item 2</li>

  <li>item 3</li>

  ......

  <li>item n</li>

</ul>

// ...... 代表中間還有未知數個 li

如果給每個列表項一一都綁定一個函數,那對于內存消耗是非常大的,效率上需要消耗很多性能;

 

因此,比較好的方法就是把這個點擊事件綁定到他的父層,也就是 `ul` 上,然后在執行事件的時候再去匹配判斷目標元素;

 

所以事件委托可以減少大量的內存消耗,節約效率。

 

2. 動態綁定事件

 

比如上述的例子中列表項就幾個,我們給每個列表項都綁定了事件;

 

在很多時候,我們需要通過 ajax 或者用戶操作動態的增加或者去除列表項元素,那么在每一次改變的時候都需要重新給新增的元素綁定事件,給即將刪去的元素解綁事件;

 

如果用了事件委托就沒有這種麻煩了,因為事件是綁定在父層的,和目標元素的增減是沒有關系的,執行到目標元素是在真正響應執行事件函數的過程中去匹配的;

 

所以使用事件在動態綁定事件的情況下是可以減少很多重復工作的。

 

jQuery 中的事件委托

 

jQuery 中的事件委托相信很多人都用過,它主要這幾種方法來實現:

 

$.on: 基本用法 : $('.parent').on('click', 'a', function () { console.log('click event on tag a'); }) ,它是 .parent 元素之下的 a 元素的事件代理到 $('.parent') 之上,只要在這個元素上有點擊事件,就會自動尋找到 .parent 元素下的 a 元素,然后響應事件;

$.delegate: 基本用法 : $('.parent').delegate('a', 'click', function () { console.log('click event on tag a'); }) ,同上,并且還有相對應的 $.delegate 來刪除代理的事件;

$.live: 基本使用方法 : $('a', $('.parent')).live('click', function () { console.log('click event on tag a'); }) ,同上,然而如果沒有傳入父層元素 $(.parent) ,那事件會默認委托到 $(document) 上; ( 已廢除 )

實現功能

 

基本實現

 

比如我們有這樣的一個 HTML 片段:

 

<ul id="list">

  <li>item 1</li>

  <li>item 2</li>

  <li>item 3</li>

  ......

  <li>item n</li>

</ul>

// ...... 代表中間還有未知數個 li

我們來實現把 #list 下的 li 元素的事件代理委托到它的父層元素也就是 #list 上:

 

// 給父層元素綁定事件

document.getElementById('list').addEventListener('click', function (e) {

  // 兼容性處理

  var event = e || window.event;

  var target = event.target || event.srcElement;

  // 判斷是否匹配目標元素

  if (target.nodeName.toLocaleLowerCase === 'li') {

    console.log('the content is: ', target.innerHTML);

  }

});

在上述代碼中, target 元素則是在 #list 元素之下具體被點擊的元素,然后通過判斷 target 的一些屬性(比如: nodeName , id 等等)可以更精確地匹配到某一類 #list li 元素之上;

 

使用 Element.matches 精確匹配

 

如果改變下 HTML 成:

 

<ul id="list">

  <li className="class-1">item 1</li>

  <li>item 2</li>

  <li className="class-1">item 3</li>

  ......

  <li>item n</li>

</ul>

// ...... 代表中間還有未知數個 li

這里,我們想把 #list 元素下的 li 元素(并且它的 class 為 class-1 )的點擊事件委托代理到 #list 之上;

 

如果通過上述的方法我們還需要在 `if (target.nodeName.toLocaleLowerCase === 'li')` 判斷之中在加入一個判斷 `target.nodeName.className === 'class-1'` ;

 

但是如果想像 CSS 選擇其般做更加靈活的匹配的話,上面的判斷未免就太多了,并且很難做到靈活性,這里可以使用 Element.matches API 來匹配;

 

Element.matches API 的基本使用方法 : Element.matches(selectorString) , selectorString 既是 CSS 那樣的選擇器規則,比如本例中可以使用 target.matches('li.class-1') ,他會返回一個布爾值,如果 target 元素是標簽 li 并且它的類是 class-1 ,那么就會返回 true ,否則返回 false ;

 

當然它的兼容性還有一些問題,需要 IE9 及以上的現代化瀏覽器版本;

 

我們可以使用 Polyfill 來解決兼容性上的問題:

 

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;            

    };

}

加上 Element.matches 之后就可以來實現我們的需求了:

 

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;            

    };

}

document.getElementById('list').addEventListener('click', function (e) {

  // 兼容性處理

  var event = e || window.event;

  var target = event.target || event.srcElement;

  if (target.matches('li.class-1')) {

    console.log('the content is: ', target.innerHTML);

  }

});

函數封裝

 

在應對更多場景上我們可以把事件代理的功能封裝成一個公用函數,這樣就可以重復利用了。

結合上面的例子來實現一個函數 eventDelegate ,它接受四個參數:

 

[String] 一個選擇器字符串用于過濾需要實現代理的父層元素,既事件需要被真正綁定之上;

[String] 一個選擇器字符串用于過濾觸發事件的選擇器元素的后代,既我們需要被代理事件的元素;

[String] 一個或多個用空格分隔的事件類型和可選的命名空間,如 click 或 keydown.click ;

[Function] 需要代理事件響應的函數;

這里就有幾個關鍵點:

 

對于父層代理的元素可能有多個,需要一一綁定事件;

對于綁定的事件類型可能有多個,需要一一綁定事件;

在處理匹配被代理的元素之中需要考慮到兼容性問題;

在執行所綁定的函數的時候需要傳入正確的參數以及考慮到 this 的問題;

function eventDelegate (parentSelector, targetSelector, events, foo) {

  // 觸發執行的函數

  function triFunction (e) {

    // 兼容性處理

    var event = e || window.event;

    var target = event.target || event.srcElement;

    // 處理 matches 的兼容性

    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;            

        };

    }

    // 判斷是否匹配到我們所需要的元素上

    if (target.matches(targetSelector)) {

      // 執行綁定的函數,注意 this

      foo.call(target, Array.prototype.slice.call(arguments));

    }

  }

  // 如果有多個事件的話需要全部一一綁定事件

  events.split('.').forEach(function (evt) {

    // 多個父層元素的話也需要一一綁定

    Array.prototype.slice.call(document.querySelectorAll(parentSelector)).forEach(function ($p) {

      $p.addEventListener(evt, triFunction);

    });

  });

}

優化

 

當被代理的元素不是目標元素的時候,既選擇器 targetSelector 所指向的元素不是 event.target (事件目標階段指向的元素)的時候,這時候就需要層層遍歷 event.target 的 parentNode 去匹配 targetSelector 了,直到 parentSelector 。

 

比如:

 

<ul id="list">

  <li><span>item 1</span></li>

  <li><span>item 2</span></li>

</ul>

還是把 li 的事件代理到 #list 之上,但這時候會發現 event.target 指向的是 li span ,因此需要層層遍歷外層元素去匹配,直到到代理事件的函數,我們可以用 event.currentTarget 來獲取到代理事件的函數;

 

完整函數:

 

function eventDelegate (parentSelector, targetSelector, events, foo) {

  // 觸發執行的函數

  function triFunction (e) {

    // 兼容性處理

    var event = e || window.event;

 

    // 獲取到目標階段指向的元素

    var target = event.target || event.srcElement;

 

    // 獲取到代理事件的函數

    var currentTarget = event.currentTarget;

 

    // 處理 matches 的兼容性

    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;            

        };

    }

 

    // 遍歷外層并且匹配

    while (target !== currentTarget) {

      // 判斷是否匹配到我們所需要的元素上

      if (target.matches(targetSelector)) {

        var sTarget = target;

        // 執行綁定的函數,注意 this

        foo.call(sTarget, Array.prototype.slice.call(arguments))

      }

 

      target = target.parentNode;

    }

  }

 

  // 如果有多個事件的話需要全部一一綁定事件

  events.split('.').forEach(function (evt) {

    // 多個父層元素的話也需要一一綁定

    Array.prototype.slice.call(document.querySelectorAll(parentSelector)).forEach(function ($p) {

      $p.addEventListener(evt, triFunction);

    });

  });

}

使用函數:

 

eventDelegate('#list', 'li', 'click', function () { console.log(this); });

點擊后可以看到 console 出了 `#list li` 元素對象;

 

局限性

 

當然,事件委托也是有一定局限性的;

 

比如 focus 、 blur 之類的事件本身沒有事件冒泡機制,所以無法委托;

 

mousemove 、 mouseout 這樣的事件,雖然有事件冒泡,但是只能不斷通過位置去計算定位,對性能消耗高,因此也是不適合于事件委托的;

新聞名稱:好程序員分享JavaScript事件委托代理和函數封裝詳解-創新互聯
網站地址:http://www.js-pz168.com/article18/ddpidp.html

成都網站建設公司_創新互聯,為您提供網頁設計公司移動網站建設電子商務網站內鏈品牌網站制作網站制作

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

網站托管運營
久久99久久人婷婷精品综合_超碰aⅴ人人做人人爽欧美_亚洲电影第三页_日韩欧美一中文字暮专区_波多野结衣的一区二区三区_婷婷在线播放_人人视频精品_国产精品日韩精品欧美精品_亚洲免费黄色_欧美性猛交xxxxxxxx
精品国产乱码久久久久久108| 在线成人小视频| 欧美一区二区大片| 亚洲欧洲国产专区| 奇米精品一区二区三区在线观看| 成人黄色小视频在线观看| 欧美日韩视频在线一区二区观看视频| 欧美三级在线视频| 中文字幕国产一区二区| 免费成人在线观看| av日韩免费电影| 色婷婷一区二区| 欧美激情一区二区三区全黄 | 亚洲成av人影院在线观看网| 国产成a人亚洲| 欧美在线一二三区| 日韩西西人体444www| 亚洲精品自拍动漫在线| 国产69精品久久久久毛片| 日本在线播放一区| 日韩欧美国产一区二区三区 | 色天使色偷偷av一区二区| 久久免费看少妇高潮| 亚洲二区视频在线| 91丝袜美腿高跟国产极品老师 | 亚洲va欧美va人人爽| 99麻豆久久久国产精品免费| 亚洲精品自在在线观看| 久久久国产精品午夜一区ai换脸| 日本午夜一本久久久综合| 国产高清精品一区二区| 欧美日韩精品高清| 一区二区三区.www| 91麻豆免费视频| 欧美日韩一区二区欧美激情| 亚洲精品中文字幕乱码三区 | 美女网站一区二区| 久久伦理网站| 精品久久久久久最新网址| 日韩精品福利网| 国产亚洲精品自在久久| 91精品国产综合久久香蕉的特点| 亚洲一区在线观看网站| 91在线看国产| 欧美情侣在线播放| 亚洲成人av中文| 国产日本一区二区三区| 日韩精品综合一本久道在线视频| 日日骚欧美日韩| 久久国产主播精品| 欧美精品一区二区三区蜜桃| 毛片av一区二区| 欧洲精品国产| 国产精品视频一区二区三区不卡| 国产成人综合在线观看| 色视频一区二区| 亚洲精品免费一二三区| 99电影在线观看| 日韩免费观看高清完整版在线观看| 日韩电影一二三区| 日本亚洲欧洲精品| 国产精品久久久久毛片软件| 白白色亚洲国产精品| 欧美狂野另类xxxxoooo| 日韩电影在线一区二区三区| 欧美日韩亚洲一区二区三区在线观看| 国产亚洲一区二区三区四区| 国产成人在线网站| 欧美日韩在线播放三区| 日本最新不卡在线| 欧美乱偷一区二区三区在线| 国产精品久久毛片| 91视频免费在线观看| 日韩精品一区二区三区中文不卡 | 亚洲午夜精品在线| 麻豆蜜桃91| 国产精品久久久久久久久免费樱桃| caoporm超碰国产精品| 91精品国产综合久久香蕉麻豆| 蜜桃传媒麻豆第一区在线观看| 色一情一区二区三区四区| 亚洲精品午夜久久久| 精品国产91亚洲一区二区三区www| 久久久国产一区二区三区四区小说| 成人黄页在线观看| 日韩精品中文字幕在线不卡尤物| 国产一本一道久久香蕉| 欧美日韩日日摸| 极品少妇xxxx精品少妇| 欧美图片一区二区三区| 日本vs亚洲vs韩国一区三区二区 | 欧美一区二区三区四区五区| 国内精品伊人久久久久影院对白| 欧美色图天堂网| 久久精工是国产品牌吗| 欧美视频在线观看一区二区| 蜜臀av性久久久久av蜜臀妖精| 一本在线高清不卡dvd| 日韩精品一二三四| 91成人看片片| 美洲天堂一区二卡三卡四卡视频| 色哟哟一区二区| 麻豆精品新av中文字幕| 欧美视频一区二区在线观看| 久久91精品国产91久久小草| 欧美日韩一二区| 国产成人免费在线观看| 日韩一区二区在线观看| 成人免费视频播放| 欧美精品一区二区在线观看| 91无套直看片红桃| 中文在线资源观看网站视频免费不卡| 成人免费视频网站| 亚洲欧美怡红院| 奇米影视首页 狠狠色丁香婷婷久久综合 | 日韩精品久久一区| 亚洲午夜av在线| 综合一区中文字幕| 美女视频黄免费的久久 | 国产jizzjizz一区二区| 欧美videos中文字幕| 91在线免费视频观看| 国产精品乱码一区二区三区软件| 久久riav| 亚洲成人久久影院| 欧美亚洲另类激情小说| 国产mv日韩mv欧美| 国产午夜精品久久久久久免费视 | 亚洲精品高清视频在线观看| 亚洲精品日韩精品| 麻豆91在线播放| 日韩一级高清毛片| αv一区二区三区| 亚洲欧美另类综合偷拍| 亚洲人成人77777线观看| 久久99久久99小草精品免视看| 日韩午夜精品视频| 成人动漫在线观看视频| 亚洲精品成人精品456| 一本大道久久精品懂色aⅴ| 国产一区二区三区观看| 久久久久亚洲蜜桃| 欧美乱偷一区二区三区在线| 蜜乳av一区二区| 精品日韩一区二区三区| 黑人中文字幕一区二区三区| 亚洲成av人在线观看| 3d成人动漫网站| 成人黄动漫网站免费| 亚洲国产一区二区a毛片| 欧美午夜精品久久久久久孕妇| fc2成人免费人成在线观看播放| 国产精品乱码妇女bbbb| 正在播放一区| youjizz久久| 亚洲免费观看高清完整| 欧美在线视频全部完| 9i看片成人免费高清| 一区二区三区中文在线| 欧美日韩国产综合一区二区三区| 97精品国产97久久久久久久久久久久| 亚洲品质自拍视频网站| 欧美在线视频全部完| 91麻豆.com| 亚洲va欧美va人人爽午夜| 日韩一级精品视频在线观看| 久久久久久久久久码影片| 麻豆精品国产传媒mv男同| 久久夜色精品一区| 日韩在线电影一区| 成人三级在线视频| 一区二区三区日韩精品视频| 欧美日韩国产高清一区二区三区 | 精品国精品国产| 日本欧美色综合网站免费| 国产一区二区三区免费看 | www欧美成人18+| 少妇免费毛片久久久久久久久 | 欧美一区二区播放| 欧美日本韩国在线| 国产精品一卡二卡| 亚洲欧美视频在线观看| 欧美三级中文字| 精品一区二区三区国产| 精品亚洲国产成人av制服丝袜| 国产欧美精品国产国产专区| 色94色欧美sute亚洲线路二| 99电影在线观看| 麻豆高清免费国产一区| 国产精品午夜在线| 欧美色综合网站| 精品国产免费久久久久久尖叫| 国产在线精品一区二区不卡了 | 国产自产高清不卡| 亚洲人成网站色在线观看| 日韩一区二区高清| 亚洲免费精品视频| 91成人理论电影| 精品一区二区三区视频在线观看 | 国产片一区二区|