Vanilla JS事件委托 - 处理目标元素的子元素

And*_*lly 21 javascript dom publish-subscribe event-delegation

我正试图在vanilla JS中进行事件委托.我有一个像这样的容器内的按钮

<div id="quiz">
    <button id="game-again" class="game-again"><span class="icon-spinner icon"></span><span>Go again</span></button>
</div>
Run Code Online (Sandbox Code Playgroud)

按照David Walsh的不错说明,我正在向按钮的祖先添加一个事件处理程序,如下所示:

this.container.addEventListener('click', function(e){
    if (e.target && e.target.id == 'game-again') {
        e.stopPropagation();
        self.publish('primo:evento');
    }
});
Run Code Online (Sandbox Code Playgroud)

this.container是#quiz元素.这有一半的时间,但其余的时间click事件的目标是按钮内的跨度之一,所以我的事件处理程序不会被调用.处理这种情况的最佳方法是什么?

Ben*_*aum 35

较新的浏览器

较新的浏览器支持.matches:

this.container.addEventListener('click', function(e){
    if (e.target.matches('#game-again,#game-again *')) {
        e.stopPropagation();
        self.publish('primo:evento');
    }
});
Run Code Online (Sandbox Code Playgroud)

你可以得到没有前缀的版本

var matches = document.body.matchesSelector || document.body.webkitMatchesSelector || document.body.mozMatchesSelector || document.body.msMatchesSelector || document.body.webkitMatchesSelector
Run Code Online (Sandbox Code Playgroud)

然后.apply用于更多浏览器(仍然是IE9 +).

较旧的浏览器

假设你必须支持旧的浏览器,你可以走DOM:

function hasInParents(el,id){
    if(el.id === id) return true; // the element
    if(el.parentNode) return hasInParents(el.parentNode,id); // a parent
    return false; // not the element nor its parents
}
Run Code Online (Sandbox Code Playgroud)

但是,这将爬上整个dom,你想停在代表团的目标:

function hasInParentsUntil(el,id,limit){
    if(el.id === id) return true; // the element
    if(el === limit) return false;
    if(element.parentNode) return hasInParents(el.parentNode,id); // a parent
    return false; // not the element nor its parents
}
Run Code Online (Sandbox Code Playgroud)

哪个,会使你的代码:

this.container.addEventListener('click', function(e){
    if (hasInParentsUntil(e.target,'game-again',container)) { // container should be 
        e.stopPropagation();                                  // available for this
        self.publish('primo:evento');
    }
});
Run Code Online (Sandbox Code Playgroud)

  • 你已经在你的例子中输入了两次`document.body.matchesSelector`. (2认同)
  • @Tomas将答案写为*回答问题*。期望读者能够使用自己的批判性思维技能来确定答案的哪些部分与他们自己的需求相关。如果您认为可以写出更好的答案,我鼓励您这样做。 (2认同)

c_o*_*goo 7

替代解决方案:

MDN:指针事件

为所有嵌套的子元素添加一个类 ( .pointer-none)

.pointer-none {
  pointer-events: none;
}
Run Code Online (Sandbox Code Playgroud)

你的加价变成

<div id="quiz">
    <button id="game-again" class="game-again">
        <span class="icon-spinner icon pointer-none"></span>
        <span class="pointer-none">Go again</span>
    </button>
</div>
Run Code Online (Sandbox Code Playgroud)

将指针设置为 none 时,不会在这些元素上触发 click 事件。

https://css-tricks.com/slightly-careful-sub-elements-clickable-things/