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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24117369/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 02:12:27  来源:igfitidea点击:

Vanilla JS event delegation - dealing with child elements of the target element

javascriptdompublish-subscribeevent-delegation

提问by And Finally

I'm trying to do event delegation in vanilla JS. I have a button inside a container like this

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

<div id="quiz">
    <button id="game-again" class="game-again">
        <span class="icon-spinner icon"></span>
        <span>Go again</span>
    </button>
</div>

And following David Walsh's nice instructionsI'm adding an event handler to an ancestor of the button like so:

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

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

Where this.containeris the #quiz element. This works half the time, but the rest of the time the target of the click event is one of the spans inside the button, so my event handler isn't called. What's the best way to deal with this situation?

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

采纳答案by C_Ogoo

Alternate Solution:

替代解决方案:

MDN: Pointer events

MDN:指针事件

Add a class to all nested child elements (.pointer-none)

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

.pointer-none {
  pointer-events: none;
}

Your mark-up becomes

你的加价变成

<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>

With the pointer set to none, the click event wouldn't fire on those elements.

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

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

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

回答by Benjamin Gruenbaum

Newer browsers

较新的浏览器

Newer browsers support .matches:

较新的浏览器支持.matches

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

You can get the unprefixed version with

您可以获得无前缀的版本

var matches = document.body.matchesSelector || document.body.webkitMatchesSelector || document.body.mozMatchesSelector || document.body.msMatchesSelector || document.body.webkitMatchesSelector

And then use .applyfor more browsers (Still IE9+).

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

Older browsers

较旧的浏览器

Assuming you have to support older browsers, you can walk up the DOM:

假设您必须支持旧浏览器,您可以向上走 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
}

However, this will climb the whole dom, and you want to stop at the delegation target:

但是,这将爬上整个 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
}

Which, would make your code:

其中,将使您的代码:

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');
    }
});