Tengo la siguiente estructura:

<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>
  • Hay más de 1 elemento <li>
  • Todos los atributos data- están en los elementos <li>

Usando jQuery, generalmente haría uso de la delegación de eventos en lugar de adjuntar controladores de eventos en cada elemento <li>:

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

Sin embargo, no puedo replicar esto usando JavaScript puro. Quiero poder hacer clic en un elemento <li> sin hacer clic en ninguno de sus elementos secundarios.

Tampoco tengo la libertad de usar más cercano () ya que tenemos que proporcionar soporte para IE11. ¿Hay una manera más sencilla de implementarlo?

EDITAR: Estoy evitando adjuntar oyentes de eventos a cada elemento <li> ya que no funcionará para elementos creados <li> dinámicamente, y también por razones de rendimiento.

3
Siddharth Thevaril 9 may. 2019 a las 17:36

4 respuestas

La mejor respuesta

Puede deshabilitar el contenido del li para que no reciba ningún evento del mouse configurando un 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>

Ahora puede garantizar que event.target siempre será li

2
Rannie Aguilar Peralta 9 may. 2019 a las 14:49

¿Algo como get all li y adjuntar un eventlistener hacer?

<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>
0
Carlos Alves Jorge 9 may. 2019 a las 14:43

Aquí hay un ejemplo usando Element.closest () , para el cual hay un 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>

Editar : esto no funcionará en IE, ya que es probable que stackoverflow no cargue el polyfill. Pero si lo prueba de forma independiente (debe durar 3 segundos) puede verificar si es lo suficientemente bueno para usted.

0
Zlatko 9 may. 2019 a las 14:56

Si no desea adjuntar el controlador de eventos en todos los elementos directamente. puede adjuntar solo un controlador de eventos en el padre como este

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

Lápiz que demuestra lo mismo: https://codepen.io/kireeti-tiki/pen / EzPpqZ? Editors = 1010

Utilicé compositePath en el objeto de evento para llegar a li, no lo recomendaría, ya que esta es una forma un poco hacky de llegar a la solución. Además, no es compatible con IE y Edge. Manténgase alejado de esa solución si necesita soporte para esos navegadores. Más sobre ese tema aquí https://developer.mozilla.org/en -US / docs / Web / API / Event

Si usar jQuery no es un problema, entonces recomendaría ese enfoque.

1
Kireeti K 9 may. 2019 a las 17:41