将jQuery.on(event,selector,func)转换为.addEventListener(event,func),尤其是遵循DOM树的选择器部分和事件气泡

时间:2018-07-15 19:42:22

标签: javascript jquery addeventlistener dom-events jquery-events

我想将项目中的代码从jQuery.on转换为.addEventListener,并消除对jQuery的依赖。

主要问题:有没有办法用相对较少的代码来做到这一点,还是我需要编写一个自定义事件处理程序(如jQuery似乎有的?)?

------------------------------------------
|                   a                    |
|                                        |
|     -----------------------------      |
|     |             b             |      |
|     |                           |      |
|     |      ---------------      |      |
|     |      |      c      |      |      |
|     |      |             |      |      |
|     |      |             |      |      |
|     |      |             |      |      |
|     |      |             |      |      |
|     |      |             |      |      |
|     |      ---------------      |      |
|     |                           |      |
|     |                           |      |
|     -----------------------------      |
|                                        |
|                                        |
------------------------------------------

点击 c ,应返回 c 的处理程序,然后依次是 b a

我已经阅读了多个stackoverflow问题*和答案,这使我对两者之间的区别有一个基本的了解(或者主要是jQuery添加的附加逻辑)。在此fiddle中,您可以看到一个我想以jQuery工作方式工作的基本示例。

我很清楚,当事件从目标(div.c)起泡时,事件到达div.a,然后div.a上的侦听器按添加顺序被触发,在此示例中,结果是 b ,c而不是c,b,类似于jQuery。

b 为粗体,因为尽管这是期望的行为,但它不会被触发。 之所以不会被触发,是因为e.target(div.c)与querySelector .b不匹配。

在我看来,当从.addEventHandler触发事件时,jQuery会使用自己的事件处理/触发。 而且,即使侦听器是从公共父级触发的,似乎也要考虑到DOM嵌套。 考虑到DOM嵌套的最后一部分是我想要使用“ vanilla” js。

使用$._data(element, 'events'),我们可以访问jQuery内部存储的事件以查看它们。 这里的guid属性似乎指示事件被触发的顺序。 如何确定/触发订单,但是我找不到。

我们非常感谢您的帮助!

*相关问题

jQuery .on(); vs JavaScript .addEventListener();

jQuery event handlers always execute in order they were bound - any way around this?

jQuery on() stopPropagation not working?

1 个答案:

答案 0 :(得分:1)

您可以遍历目标的所有祖先,并检查它们是否与特定选择器匹配,并为每个匹配的实例调用回调

它们触发的顺序仍然是它们添加到根元素的顺序

HTMLElement.prototype.delegate = function(evtName, selector, callback) {
  var rootElement = this;


  this.addEventListener(evtName, function(e) {
    var matchingAncestors = [], parent = e.target.parentElement;
    // TODO: Abort if target is root element

    if (e.target.matches(selector)) {
       console.log('selector', selector,'matches target')
      callback(e)
    } else {
      // we know it's not the target so work way up ancestors finding selector matches     
      while (parent && parent !== rootElement) {
        if (parent.matches(selector)) {
          matchingAncestors.push(parent)
        }
        parent = parent.parentElement
      }

      // call the callback for each instance
      matchingAncestors.forEach(function(el) {
        console.log(el, ' is matching ancestor of target')
        callback(e)
      });
    }
  })

}
   
var a = document.querySelector(".a");

a.addEventListener("click", function(e) {
  console.log('*********************************')
  console.log("Vanilla a\n");
});
a.delegate('click', '.b', function(e) {
  console.log("Vanilla-delegate b\n");
})

a.delegate('click', '.c', function(e) {
  console.log("Vanilla-delegate c\n");
})
div {padding-left:30px; border:1px solid #ccc}
<div class="a">
  a
  <div class="b">
    b
    <div class="c">
      c<br>(click me)
    </div>
  </div>
</div>

请注意,这未经生产测试