简体   繁体   English

当事件处理程序附加到父级时,防止在某个子级之后单击

[英]Prevent click after a certain child when event handler is attached to parent

I have the following structure: 我有以下结构:

<ul id="list-items">
    <li class="item" data-id="123" data-title="Some Title">
        <div class="block">
            <img src="#"/>
            <a href="#">Link</a>
            <p>Some excerpt</p>
        </div>
    </li>
</ul>
  • There are more than 1 <li> item 有超过1个<li>项目
  • All data- attributes are on the <li> elements 所有data-属性都在<li>元素上

Using jQuery, I would usually make use of event delegation instead of attaching event handlers on every <li> item: 使用jQuery,我通常会使用事件委托,而不是在每个<li>项目上附加事件处理程序:

$( document ).on( 'click', '.item', function() {
    var id    = $( this ).data( 'id' );
    var title = $( this ).data( 'title' );
});

However, I am not able to replicate this using Pure JavaScript. 但是,我无法使用Pure JavaScript复制它。 I want to be able to click on an <li> item without clicking any of its child elements. 我希望能够点击<li>项而不点击任何子元素。

I am also not at the liberty of using closest() since we have to provide support for IE11. 我也不能使用nearest(),因为我们必须为IE11提供支持。 Is there a simpler way to implement it? 有没有更简单的方法来实现它?

EDIT: I am avoiding attaching event listeners to each <li> item as it won't work for dynamically created <li> elements, and also for performance reasons. 编辑:我避免将事件监听器附加到每个<li>项目,因为它不适用于动态创建的<li>元素,也出于性能原因。

You can disable the li 's content from getting any mouse event by setting a pointer-events: none to it. 您可以通过设置pointer-events: none来禁用li的内容来获取任何鼠标事件。

<li class="item" data-id="123" data-title="Some Title">
    <div class="block" style="pointer-events: none">
        <img src="#"/>
        <a href="#">Link</a>
        <p>Some excerpt</p>
    </div>
</li>

You can guarantee now that the event.target will always be the li 你现在可以保证event.target永远是li

If you don't want to attach event handler on all the items directly. 如果您不想直接在所有项目上附加事件处理程序。 you can attach only one event handler on the parent like this 您可以像这样只在父级上附加一个事件处理程序

var element = document.querySelector("#vanilla-parent")
element.addEventListener("click", function(event){
  event.composedPath().forEach(function(elm){
    if (elm.tagName === 'LI') {
      // do something
    }
  });
});

$("#jquery-parent").on("click", "li", function(event){
   // do something
});

Pen demonstrating the same: https://codepen.io/kireeti-tiki/pen/EzPpqZ?editors=1010 笔展示相同: https//codepen.io/kireeti-tiki/pen/EzPpqZ?edit = 1010

I used composedPath on the event object to get to li, I wouldn't recommend this as this is a bit of hacky way to get to the solution. 我在事件对象上使用了composPath来获取li,我不推荐这个,因为这是一个讨厌解决方案的hacky方式。 Also, it is not supported on IE and Edge. 此外,IE和Edge不支持它。 So stay away from that solution if you need support for those browsers. 如果您需要对这些浏览器的支持,请远离该解决方案。 More on that subject here https://developer.mozilla.org/en-US/docs/Web/API/Event 有关该主题的更多信息,请访问https://developer.mozilla.org/en-US/docs/Web/API/Event

If using jQuery is not a problem, Then I would recommend that approach. 如果使用jQuery不是问题,那么我会推荐这种方法。

Will something like get all li and attach an eventlistener do? 像获得所有li并附加eventlistener一样吗?

<script>

    var li_list = document.getElementsByTagName('li');

    for(var i = 0; i < li_list.length; i++) {
        (function(index) {
            li_list[index].addEventListener("click", function() {
                event.preventDefault();
                alert('clicked')
            })
        })(i);
    }
</script>

Here's an example using Element.closest() , for which there is a polyfill. 这是使用Element.closest()的示例,其中有一个polyfill。

 function attachClickHandler() { const list = document.querySelector('.list'); list.addEventListener('click', (item) => { // console.log('Item:', item); const closest = item.target.closest('li'); console.log('Closest li:', closest); console.log('Data on closest li:', closest.tagName, closest.dataset && closest.dataset.id || 'no data'); // alternative console.log(' === alt ==='); let elem = item.target; while (elem.tagName.toLowerCase() !== 'li') { elem = elem.parentNode; if (elem.tagName.toLowerCase() === 'ul') { break; } } console.log('Manual version:', elem.tagName, elem.dataset && elem.dataset.id || 'no data'); }); console.log('Listening.'); } attachClickHandler(); 
 <h1>My list</h1> <ul class="list"> <li data-id="1">Item 1</li> <li data-id="2"><button>Item 2</button></li> <li>Empty item</li> </ul> 

Edit : This won't work on IE as stackoverflow likely doesn't load the polyfill. 编辑 :这不适用于IE,因为stackoverflow可能无法加载polyfill。 But if you test it standalone (should be 3 seconds work) you can verify if it's good enough for you. 但如果你单独测试它(应该是3秒工作),你可以验证它是否足够好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM