Делегирование событий Javascript, обработка родительских элементов с щелчком?

http://jsfiddle.net/walkerneo/QqkkA/

Я видел много вопросов здесь или спрашивал или отвечал на делегирование событий в javascript, но я еще не видел, как использовать делегирование событий для элементов, которые не станут объектами щелкните событие.

Например:

HTML:

<ul>
    <li><div class="d"></div></li>
    <li><div class="d"></div></li>
    <li><div class="d"></div></li>
    <li><div class="d"></div></li>
    <li><div class="d"></div></li>
    <li><div class="d"></div></li>
</ul>​

CSS

ul{
    padding:20px;
}
li{
    margin-left:30px;
    margin-bottom:10px;
    border:1px solid black;

}
.d{
    padding:10px;
    background:gray;
}
​

Что делать, если я хочу добавить событие click для обработки элементов li при нажатии? Если я присоединю обработчик события к элементу ul, div всегда будет целевыми элементами. Помимо проверки каждого родителя целевого элемента в функции щелчка, как я могу это сделать?

изменить:

Я хочу использовать делегирование событий вместо:

var lis = document.getElementsByTagName('li');
for(var i=0;i<lis.length;i++){
    lis[i].onclick = function(){};
}

Но если я это сделаю:

document.getElementsByTagName('ul')[0].addEventListener('click',function(e){

    // e.target is going to be the div, not the li
    if(e.target.tagName=='LI'){

    } 
},false);

EDIT: Мне не интересно, как использовать библиотеки JavaScript для этого, мне интересно, как они это делают и как это можно сделать с помощью чистого js.

Ответы

Ответ 1

Вот один из способов его решения:

var list = document.getElementsByTagName('ul')[0]

list.addEventListener('click', function(e){
  var el = e.target
  // walk up the tree until we find a LI item
  while (el && el.tagName !== 'LI') {
     el = el.parentNode
  }
  console.log('item clicked', el)
}, false)

Это слишком упрощено, цикл продолжит движение по дереву даже через элемент UL. Для более полного примера см. Реализацию rye/events.

Element.matches, Node.contains и Node.compareDocumentPosition могут помочь вам реализовать этот тип функций.

Ответ 2

Теперь есть метод для элементов, называемых closest, что делает именно это. Он выбирает селектор CSS как параметр и находит ближайшего совпадающего предка, который может быть самим элементом. Все текущие версии настольных браузеров поддерживают его, но в целом он не готов к использованию. Следующая страница MDN содержит polyfill.

Ответ 3

Я не javascript geek, но чтобы ответить на ваш вопрос (только для любопытства), я провел некоторое время в Интернете, и через пару минут я понял, что вы можете инициировать событие на родительском элементе также так ( как альтернативная идея, может быть, я не уместен), чтобы обращаться с родителями щелкнувших элементов

var el=document.getElementsByTagName('ul')[0];
el.addEventListener('click',function(e){
    var elm=e.target.parentNode;
    if(document.createEvent)
    { 
        evt = document.createEvent('MouseEvents'); 
        evt.initMouseEvent("click", false, true, window,
0, 0, 0, 0, 0, false, false, false, false, 0, null);
        elm.dispatchEvent(evt);
        liEventhandler(evt);           
    } 

});

function liEventhandler(e)
{
    console.log(e);
    console.log(e.target);
    console.log(e.which);
    alert(e.target.innerHTML);
}

Пример здесь.

Выше пример не будет работать в IE использует createEventObject и fireEvent

if(document.createEventObject)
{
    var evt = document.createEventObject();
    el.fireEvent('onclick', evt);
    liEventhandler(evt);
}

а также e.target - window.event.srcElement и addEventListener должно быть

el.attachEvent('onclick', function(){...})

Когда событие срабатывает в ul, а цель - div Я только что вызвал событие на li

Некоторые ссылки: 1. comp.lang.javascript 2. MOZILLA DEVELOPER NETWORK и 3. это.