Мне нужно выбрать элементы списка из списка, а затем выполнить такие операции, как добавление к ним обработчиков событий. Я могу придумать два способа сделать это.
HTML:
<ul id = "list">
<li id = "listItem-0"> first item </li>
<li id = "listItem-1"> second item </li>
<li id = "listItem-2"> third item </li>
</ul>
Используя идентификаторы-
for(i=0;i<3;i++)
{
document.getElementById("listItem-"+i).addEventListener("click",foo,false);
}
Использование свойства childNodes -
for(i=0;i<3;i++)
{
document.getElementById("list").childNodes[i]
.addEventListener("click",foo,false);
}
Причина, по которой я использую первый подход, заключается в том, что в функции foo, если мне нужен индекс, по которому элемент находится в списке, я могу сделать это, разделив идентификатор -
function foo()
{
tempArr = this.id.split('-');
index = tempArr[tempArr.length-1]; // the last element in the array
}
Я не могу придумать, как это сделать, используя второй метод, то есть без использования схемы именования идентификаторов.
Вопросы:



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вы можете избежать добавления обработчиков событий к каждому элементу списка, добавив один обработчик событий к содержащему элементу (неупорядоченный список) и используя концепцию восходящей цепочки событий. В этом единственном обработчике событий вы можете использовать свойства объекта события, чтобы определить, что было выбрано.
Похоже, вы хотите сопоставить данные в массиве с элементами списка. Хотя синтаксический анализ индекса массива из идентификатора элемента списка будет работать, другой подход будет заключаться в том, чтобы сохранить значение «ключа» в элементе списка как раскрываемое и использовать свойства объекта javascript для поиска ваших данных.
Частичный пример:
<li key = "myKey">
//oData is a object (eg. var oData = {};) that has been populated with properties
//whose value is the desired data (eg. oData["myKey"] = 123;)
alert(oData[event.srcElement.key]); // alerts 123
Что касается плохих эффектов первого метода, который вы показали, один плохой эффект заключается в том, что при большом количестве элементов списка вы в конечном итоге определяете множество обработчиков событий, что в какой-то момент могло бы повлиять на производительность.
Также обратите внимание, что вы можете непреднамеренно создать глобальную переменную в своих циклах, опуская ключевое слово var для «i».
Если вы решите использовать jQuery, это будет очень просто:
$('ul#list li').click(function () {
var i = this.id.split('-').pop();
alert( i );
});
Может быть что-то похожее на:
var lis = document.getElementById("list").getElementsByTagName("li");
for (var i = 0, li; li = lis[i]; ++i) {
li.addEventListener("click", (function(pos) {
return function() {
alert(pos);
};
})(i), false);
}
Или, вдохновившись ответом J cs и настраиваемые атрибуты данных:
var lis = document.getElementById("list").getElementsByTagName("li");
for (var i = 0, li; li = lis[i]; ++i) {
li.setAttribute("data-index", i); // Or whatever value you want...
li.addEventListener("click", function() {
alert(this.getAttribute("data-index"));
}, false);
}
Как указывалось ранее, если вы хотите получить список li, вы должны использовать getElementsByTagName в своем ul, потому что childNodes может получать некоторые текстовые узлы, а также узлы li.
Теперь, если вам нужно использовать индекс в обработчике событий, вам может быть лучше напрямую использовать закрытие, чтобы повторно использовать переменную цикла внутри обработчика событий.
var lis = document.getElementById("list").getElementsByTagName("li");
for( var i = 0, l = lis.length; i < l; ++i )
{
(function(){
// As a new variable will be created for each loop,
// you can use it in your event handler
var li = lis[i];
li.addEventListener("click", function()
{
li.className = "clicked";
}, false);
})();
}
Но вы можете рассмотреть возможность делегирования событий для этой цели. Вам нужно только прикрепить обработчик событий к родительскому элементу и найти выбранный элемент с помощью атрибута target.
document.getElementById("list").addEventListener("click", function(event)
{
var li = event.target;
if ( li.nodeName.toLowerCase() == "li" )
{
...
}
}, false);
Первый метод не работает в браузерах, которые обрабатывают пробелы как текстовые узлы. Вы действительно не объясняете, почему вас волнует показатель, поэтому я не собираюсь размышлять о том, есть ли лучшие решения.