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
Vanilla JS event delegation - dealing with child elements of the target element
提问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.container
is 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:
替代解决方案:
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 .apply
for 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');
}
});