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

时间:2019-05-09 14:36:08

标签: javascript

我具有以下结构:

<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>
  • 有1个以上的<li>项目
  • 所有data-属性都在<li>元素上

使用jQuery,我通常会使用事件委托,而不是在每个<li>项目上附加事件处理程序:

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

但是,我无法使用Pure JavaScript复制此代码。 我希望能够单击一个<li>项目而不单击其任何子元素。

由于我们必须提供对IE11的支持,因此我也不愿意使用closest()。有没有更简单的方法来实现它?

编辑: 我避免将事件侦听器附加到每个<li>项目,因为它不适用于动态创建的<li>元素,并且出于性能原因。

4 个答案:

答案 0 :(得分:2)

您可以通过将li设置为pointer-events: none来禁用<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> 的内容。

event.target

您现在可以保证li始终是{{1}}

答案 1 :(得分:1)

如果您不想直接在所有项目上附加事件处理程序。您只能像这样在父级上附加一个事件处理程序

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

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

我在事件对象上使用了compositionPath来获取li,我不建议这样做,因为这是一种获取解决方案的方法。另外,IE和Edge不支持它。因此,如果您需要这些浏览器的支持,请远离该解决方案。有关该主题的更多信息,请点击https://developer.mozilla.org/en-US/docs/Web/API/Event

如果使用jQuery没问题,那么我推荐这种方法。

答案 2 :(得分:0)

会像让所有li并附加事件监听器一样吗?

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

答案 3 :(得分:0)

下面是一个使用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>

编辑:这在IE上不起作用,因为stackoverflow可能不会加载polyfill。但是,如果您独立测试它(应该工作3秒钟),则可以验证它是否对您足够好。