Heim  >  Artikel  >  Web-Frontend  >  Detaillierte Erläuterung der JavaScript-Implementierung der Ereignisdelegierungsmethode

Detaillierte Erläuterung der JavaScript-Implementierung der Ereignisdelegierungsmethode

韦小宝
韦小宝Original
2018-03-14 16:23:362168Durchsuche

In diesem Artikel geht es um die JavaScript-Implementierung der Ereignisdelegierungsmethode. Wenn Sie nichts über die JavaScript-Implementierung der Ereignisdelegierungsmethode wissen oder an der JavaScript-Implementierung der Ereignisdelegierungsmethode interessiert sind, werfen wir einen Blick darauf Dieser Artikel. Okay, lassen Sie uns den Unsinn reduzieren und auf den Punkt kommen. besteht darin, ein Ereignis zu delegieren. Die Funktion eines Elements, das auf Ereignisse (Klick, Tastendruck ...) reagiert, wird an ein anderes Element delegiert.

Im Allgemeinen werden Ereignisse eines Elements oder einer Gruppe von Elementen delegiert seine übergeordnete Ebene Oder auf dem äußeren Element ist es das äußere Element, das das Ereignis tatsächlich bindet. Wenn das Ereignis auf das zu bindende Element reagiert, löst es das Bindungsereignis seines äußeren Elements über den Ereignisblasenmechanismus aus Dann wird das äußere Element gebunden, um die Funktion auszuführen. Wenn zum Beispiel gleichzeitig ein Kurier von einem Klassenkameraden im Wohnheim ankommt, besteht eine Möglichkeit darin, ihn dummerweise einzeln abzuholen. Eine andere Möglichkeit besteht darin, die Angelegenheit dem Leiter des Wohnheims anzuvertrauen und eine Person gehen zu lassen Holen Sie alle Kuriere heraus, holen Sie sie ab und verteilen Sie sie dann einzeln an jeden Studenten im Wohnheim, je nach Empfänger.

Hier ist das Abholen der Kuriere ein Ereignis, und jeder Student bezieht sich auf das DOM-Element, das er benötigt auf das Ereignis zu reagieren, und der Wohnheimleiter, der die Expresszustellung abholt, ist das Element des Agenten, daher ist es dieses Element, das das Ereignis tatsächlich bindet. Der Prozess der Verteilung der Expresszustellung entsprechend dem Empfänger erfolgt Es muss beurteilt werden, ob das aktuelle Antwortereignis mit dem oder den Elementen im Proxy-Element übereinstimmen sollte.

Event-Bubbling

Wie bereits erwähnt, nutzt die Implementierung der Event-Delegation in DOM den Event-Bubbling-Mechanismus.

Wenn

document.addEventListener wir das Ereignismodell festlegen: Event-Bubbling, Ereigniserfassung, im Allgemeinen werden Event-Bubbling-Modelle verwendet;

Wie in der Abbildung oben gezeigt, ist das Ereignismodell in drei Phasen unterteilt:

1,
Erfassungsphase

: Im Ereignisblasenmodell , die Erfassungsphase reagiert auf keine Ereignisse

2. Die Zielphase bedeutet, dass das Ereignis auf das niedrigste Element reagiert, das das Ereignis auslöst >3.

Bubbling-Phase

: Die Bubbling-Phase bedeutet, dass die Auslösereaktion eines Ereignisses vom unteren Ziel bis zur äußersten Ebene (Wurzelknoten) erfolgt Mechanismus bindet Ereignisse, auf die die innere Schicht reagieren muss, an die äußere Schicht.

Vorteile der Delegation

1 🎜>Stellen Sie sich vor, wenn wir eine Liste mit einer großen Anzahl von Listenelementen haben, müssen wir auf ein Ereignis reagieren, wenn auf das Listenelement geklickt wird

Wenn Bindung a Funktion für jedes Listenelement verbraucht viel Speicher und Leistung.

Daher ist es eine bessere Möglichkeit, dieses Klickereignis an die übergeordnete Ebene, also „ul“, zu binden , und dann das Zielelement bei der Ausführung des Ereignisses abgleichen und beurteilen;

So kann die Ereignisdelegierung den Speicherverbrauch erheblich reduzieren und die Effizienz steigern.

2. Ereignisse dynamisch binden

Im obigen Beispiel gibt es beispielsweise nur wenige Listenelemente und wir binden Ereignisse an jedes Listenelement ;

<ul id="list">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  ......
  <li>item n</li>
</ul>
// ...... 代表中间还有未知数个 li

在很多时候,我们需要通过 AJAX 或者用户操作动态的增加或者去除列表项元素,那么在每一次改变的时候都需要重新给新增的元素绑定事件,给即将删去的元素解绑事件;

如果用了事件委托就没有这种麻烦了,因为事件是绑定在父层的,和目标元素的增减是没有关系的,执行到目标元素是在真正响应执行事件函数的过程中去匹配的;

所以使用事件在动态绑定事件的情况下是可以减少很多重复工作的。

jQuery 中的事件委托

jQuery 中的事件委托相信很多人都用过,它主要这几种方法来实现:

1、$.on: 基本用法: $('.parent').on('click', 'a', function () { console.log('click event on tag a'); }),它是 .parent 元素之下的 a 元素的事件代理到 $('.parent') 之上,只要在这个元素上有点击事件,就会自动寻找到 .parent 元素下的 a 元素,然后响应事件;

2、$.delegate: 基本用法: $('.parent').delegate('a', 'click', function () { console.log('click event on tag a'); }),同上,并且还有相对应的 $.delegate 来删除代理的事件;

3、$.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(&#39;list&#39;).addEventListener(&#39;click&#39;, function (e) {
  // 兼容性处理
  var event = e || window.event;
  var target = event.target || event.srcElement;
  // 判断是否匹配目标元素
  if (target.nodeName.toLocaleLowerCase === &#39;li&#39;) {
    console.log(&#39;the content is: &#39;, 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,它接受四个参数:

1、[String] 一个选择器字符串用于过滤需要实现代理的父层元素,既事件需要被真正绑定之上;

2、[String] 一个选择器字符串用于过滤触发事件的选择器元素的后代,既我们需要被代理事件的元素;

3、[String] 一个或多个用空格分隔的事件类型和可选的命名空间,如 click 或 keydown.click ;

4、[Function] 需要代理事件响应的函数;

这里就有几个关键点:

1、对于父层代理的元素可能有多个,需要一一绑定事件;

2、对于绑定的事件类型可能有多个,需要一一绑定事件;

3、在处理匹配被代理的元素之中需要考虑到兼容性问题;

4、在执行所绑定的函数的时候需要传入正确的参数以及考虑到 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(&#39;.&#39;).forEach(function (evt) {
    // 多个父层元素的话也需要一一绑定
    Array.prototype.slice.call(document.querySelectorAll(parentSelector)).forEach(function ($p) {
      $p.addEventListener(evt, triFunction);
    });
  });}

以上就是本篇文章的所有内容,大家要是还不太了解的话,可以自己多实现两边就很容易掌握了哦!

相关推荐:

JS事件委托实例详解

细说什么是js中的事件冒泡和事件捕获以及事件委托

事件捕获和冒泡以及事件委托对比分析

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der JavaScript-Implementierung der Ereignisdelegierungsmethode. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn