未知选择器及子元素场景下JavaScript事件委托优化方案咨询
问题描述
我有一个动态选择器linkTrigger,用于捕获元素的点击事件,但无法预知该选择器对应的元素是什么,也不清楚它是否包含子元素。使用jQuery时一切正常:
- 点击第一个绿色矩形(非数字区域),三个事件处理器均能正常工作;
- 点击第一个绿色矩形内的数字时,仅jQuery和javascript2处理器生效,这符合预期,因为点击绿色盒子内的span元素时,不满足以下判断条件:
if (e.target.classList.contains(linkTrigger.substring(1))) {
限制条件:
- 无法在不想触发点击的子元素上使用CSS
pointer-events: none,因为不清楚linkTrigger的具体内容,也不想修改其内部结构。 - javascript2处理器不支持动态元素,后续新增的
.a容器需要手动绑定该处理器。
请问是否有更优的解决方案?
示例代码
JavaScript
var linkTrigger = '.c' // jquery works fine and its live $('.wrap').on('click', linkTrigger, function(e) { var parent = $(this).closest('.a'), id = parent.attr('data-id') console.log('jquery: ' + id) }) // javascript works but not if we click on child (number span inside green rectangle) and its live. // I cant use css point-events none on children I dont want to be clicked because I dont know what linkTrigger is, neither I want to mess with its contents. document.querySelector('.wrap').addEventListener('click', function(e){ if (e.target.classList.contains(linkTrigger.substring(1))) { var parent = e.target.closest('.a'), id = parent.getAttribute('data-id') console.log('js: ' + id) } }) // javascript2 works but its not live, meaning if I add more ".a" containers I have to attach this function call to each item. document.querySelectorAll(linkTrigger).forEach(function(el){ el.addEventListener('click', function(e){ var parent = e.target.closest('.a'), id = parent.getAttribute('data-id') console.log('js2: ' + id) }) })
CSS
.a{ width:300px; height:300px; background:red; margin:1px; } .b{ width:200px; height:200px; background:blue; } .c{ width:100px; height:100px; background:green; }
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <div class="wrap"> <div class="a" data-id="0"> <div class="b"> <div class="c"><span>657567645</span></div> </div> </div> <div class="a" data-id="1"> <div class="b"> <div class="c"></div> </div> </div> </div>
解决方案
直接用原生JS就能实现和jQuery一模一样的事件委托效果:利用Element.closest()方法,在点击事件冒泡到.wrap容器时,自动找到离点击位置最近、且匹配linkTrigger选择器的元素——不管你点的是目标元素本身还是它的子元素,都能正确触发逻辑,同时完美支持后续新增的动态元素。
实现代码如下:
var linkTrigger = '.c'; document.querySelector('.wrap').addEventListener('click', function(e) { // 找到匹配选择器的最近元素(包括点击目标自身) const targetEl = e.target.closest(linkTrigger); if (targetEl) { const parent = targetEl.closest('.a'); const id = parent.getAttribute('data-id'); console.log('optimized js: ' + id); } });
方案优势
- 动态元素自动兼容:事件绑在固定的
.wrap上,后面新增的.a或.c元素无需手动绑定事件,自动生效; - 子元素点击也能触发:不用管
linkTrigger对应的元素有没有子节点,closest()会自动定位到正确的父级目标; - 不修改元素结构/样式:完全不需要设置
pointer-events: none,不会影响元素内部的其他交互; - 纯原生无依赖:无需依赖jQuery,代码更轻量。
内容的提问来源于stack exchange,提问作者Toniq
相关产品推荐
相关产品推荐

