It will be correct not to attach a handler to each list item, but to use event delegation is the first time. If you do not know what it is, then in short it is an approach, when an event is hung not on each element, but on its “container” and already in the handler there is a check on which element the event occurred and the necessary actions are taken. What you need to know to solve the problem:
1. the item on which the event occurred.
2. its index in the array.
So, everything is simple with the first item, let's check the event.target , for the second item, you can use the forEach method.
Let me remind you that the element index is necessary for us to access the desired element in the array with descriptions.
You also need a function showing the required element.
Then gathering everything in a bunch to get the following code:
// Итак получим все еобходимые нам узлы DOM, элементы списка и описания к ним сразу поместим в массив. Это понадобиться для работы с методом forEach var container = document.querySelector('.container dl'); var listItems = Array.prototype.slice.apply(container.querySelectorAll('dt')); var details = Array.prototype.slice.apply(container.querySelectorAll('dd')); // функция показа элемента, ее будем вызывать позже. function showDetails(arr, i) { arr[i].style.opacity = 1; } // вешаем обработчик на контейнер container.addEventListener('click', function(event) { event.preventDefault(); // это привычка :) отменяет действия браузера по умолчанию (полезно для обработки кликов по ссылкам..) if (event.target.tagName == 'DT') { // проверяем что событие возникло на элементе списка for (var i = 0; i < details.length; i++) { // просто проходим по массиву с описаниями и сбрасываем прозрачность. Необходимо для скрытия уже показанного описания при клике по другому элементу списка details[i].style.opacity = ''; } //Дальше на массиве с элементами списка запускаем forEach listItems.forEach(function(item, i, arr) { if (item == event.target) { // сравниваем каждый элемент массива с элементом события showDetails(details, i); // запускаем функцию показа описания } }); } }, false);
dd { opacity: 0; }
<div class="container"> <dl> <dt>элемент списка</dt> <dd>а это наверное описание термина или пункта списка</dd> <dt>элемент списка</dt> <dd>а это наверное описание термина или пункта списка</dd> <dt>элемент списка</dt> <dd>а это наверное описание термина или пункта списка</dd> <dt>элемент списка</dt> <dd>а это наверное описание термина или пункта списка</dd> <dt>элемент списка</dt> <dd>а это наверное описание термина или пункта списка</dd> </dl> </div>
PS You can use the usual for loop, but then you need to keep the current i in the closure. To do this, you can use the functional expression with an immediately called function in the body of the loop. It looks like this:
for(var i = 0; i < listItems.length; i++) { (function(i){ if(listItems[i] == event.target) { showDetails(details, i); } })(i); }
[Addition]
As Grundy correctly noted, running around the elements in a loop each time can be expensive if we have several thousand of them ...
Therefore, instead of looping, the following can be applied directly to the markup in the response:
Since the description of the list item goes right after the element itself, you can get an element in the DOM tree, standing to the right of the one that was clicked and manipulate it.
if(event.target.nextElementSibling.tagName == 'DD') { event.target.nextElementSibling.style.opacity = 1; }
onclickhandler tofunction(i){detailsList[i].className = "lesson-info-box onclick-list-item";}.bind(i). The problem is that for each function it is not the specific value of the variableithat is attached, but the variable itself. And when the handler is called, it searches for the variableiand since the loop has already been committed to finding this variable with the value 11 - vihtor