Maison  >  Article  >  interface Web  >  Explication détaillée de l'implémentation JavaScript de la méthode de délégation d'événements

Explication détaillée de l'implémentation JavaScript de la méthode de délégation d'événements

韦小宝
韦小宝original
2018-03-14 16:23:362170parcourir

Cet article parle de l'implémentation JavaScript de la méthode de délégation d'événements. Si vous ne connaissez pas l'implémentation JavaScript de la méthode de délégation d'événements ou si vous êtes intéressé par l'implémentation JavaScript de la méthode de délégation d'événements, jetons un coup d'œil à cet article. Bon, arrêtons les bêtises et entrons dans le vif du sujet

Concept de base

La délégation événementielle, en termes simples, est de déléguer un événement La fonction d'un élément répondant à des événements (clic, appui...) est déléguée à un autre élément

De manière générale, les événements d'un ou d'un groupe d'éléments sont délégués à ; sa couche parent Ou sur l'élément externe, c'est l'élément externe qui lie réellement l'événement. Lorsque l'événement répond à l'élément qui doit être lié, il déclenchera l'événement de liaison de son élément externe via le mécanisme de bouillonnement d'événements, et. alors l'élément externe sera lié à l'élément de couche pour exécuter la fonction.

Par exemple, si un coursier arrive d'un camarade de classe du dortoir en même temps, une façon est de le récupérer bêtement un par un. Une autre façon est de confier l'affaire au directeur du dortoir et de laisser partir une personne. sortir et récupérer tous les coursiers, puis les distribuer à chaque étudiant du dortoir un par un selon le destinataire

Ici, récupérer les coursiers est un événement, et chaque étudiant se réfère à l'élément DOM dont il a besoin ; pour répondre à l'événement, et Le chef de dortoir qui sort récupérer la livraison express est l'élément de l'agent, c'est donc cet élément qui lie réellement l'événement. Le processus de répartition de la livraison express selon le destinataire est dans le. exécution de l'événement. Il faut juger que l'événement de réponse actuel doit correspondre à l'élément dans l'élément proxy.

Bulling d'événements

Comme mentionné précédemment, la mise en œuvre de la délégation d'événements dans le DOM utilise le mécanisme de bouillonnement d'événements. Alors, qu'est-ce que le bouillonnement d'événements ?

Lorsque document.addEventListener, nous pouvons définir le modèle d'événement : le bouillonnement d'événements, la capture d'événements, de manière générale, des modèles de bouillonnement d'événements sont utilisés

 ;

Comme le montre la figure ci-dessus, le modèle d'événement est divisé en trois étapes :

1, Étape de capture : Dans le modèle d'événement bouillonnant , la phase de capture ne répondra à aucun événement ;

2. Phase cible : La phase cible signifie que l'événement répond à l'élément le plus bas qui déclenche l'événement

3.

Phase de bouillonnement : La phase de bouillonnement signifie que la réponse de déclenchement d'un événement se déroulera de la cible inférieure vers la couche la plus externe (nœud racine). le mécanisme lie les événements auxquels la couche interne doit répondre à la couche externe ; ### Événements

Avantages de la délégation

1. 🎜>Imaginez, si nous avons une liste avec un grand nombre d'éléments de liste, nous devons répondre à un événement lorsque l'on clique sur l'élément de liste

Si vous liez un ; la fonction sur chaque élément de la liste un par un consommera beaucoup de mémoire et consommera beaucoup de performances
<ul id="list">
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
  ......
  <li>item n</li>
</ul>
// ...... 代表中间还有未知数个 li

Par conséquent, une meilleure façon est de lui lier cet événement de clic La couche parent, c'est-à-dire `ul` ; , puis faire correspondre et juger l'élément cible lors de l'exécution de l'événement

Ainsi, la délégation d'événements peut réduire considérablement la consommation de mémoire et gagner en efficacité ;

2. Liaison dynamique des événements

Par exemple, dans l'exemple ci-dessus, il n'y a que quelques éléments de liste et nous lions des événements à chaque élément de liste. ;

在很多时候,我们需要通过 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中的事件冒泡和事件捕获以及事件委托

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn