Страницы

Поиск по вопросам

четверг, 19 декабря 2019 г.

Цикл forEach. Обращение к элементу с index + 1

#javascript


//Есть массив со всеми картинками на странице
let all_img = document.querySelectorAll('.task-12 img');

//есть кнопка:
document.querySelector('.prev').addEventListener('touchstart', function () {

  all_img.forEach((element, index) => {
    if (element.classList.contains('active-img')) {
      element.classList.remove('active-img');
      all_img[index + 1].classList.add('active-img');
    }
  });


Если я обращаюсь к элементу с индексом + 1 - ничего не работает. Если index - 1 -
все ОК. В чем проблема? При чем, если вывести в консоль all_img[index + 1] я получу
то, что мне нужно. Но класс к этому элементу я добавить не могу.

ошибка: 

script.js:72 Uncaught TypeError: Cannot read property 'classList' of undefined
    at script.js:72
    at NodeList.forEach ()
    at HTMLButtonElement. (script.js:66)

    


Ответы

Ответ 1



если index + 1 изменить на index - 1 все работает. Не думаю. Ни у одного элемента Вашего массива нет индексированных свойств. Так что до classList дело не доходит. let a = [1, 2, 3]; a.forEach((element, index) => { if (element == 2) { console.log(element[index - 1].classList); } }); На последнем элементе Вы залезаете за границу массива. if (index < all_img.length - 1) all_img[index + 1].classList.add('active-img');

Ответ 2



Допущено три ошибки: Пренебрежение знанием о методе/типах //Есть массив со всеми картинками на странице let all_img = document.querySelectorAll('.task-12 img'); NodeList это не массив. Различие типов важно понимать, чтобы не совершать более грубых ошибок в будущем. Выход за диапазон коллекции нодов при обращении к ее элементам (как уже ответил Igor) all_img.forEach((element, index) => { // ... all_img[index + 1].classList.add('active-img'); // ... });   Алгоритмическая ошибка. Зачем каждому следующему элементу добавлять класс, а на каждой следующей итерации проверять его (класса) наличие, и удалять? Это лишено практической пользы. Циклы часто являются "узким местом" во многих смыслах, поэтому хорошей привычкой будет всегда сокращать работу в итерациях до разумного минимума (делать только то, что действительно нужно сделать). К сожалению, очень часто можно видеть как в циклах дублируются операции с DOM, напрасно инстанцируются объекты, множатся одинаковые функции листенеров событий. Сокращение подобной лишней работы - это не преоптимизация. Это повышение качества кода, и четкости его логики. Решение может быть например таким: for (var changed, i = all_img.length - 1; i >= 0; i--) { all_img[i].classList.remove('active-img'); if (!changed && i && all_img[i - 1].classList.contains('active-img')) { all_img[i].classList.add('active-img'); changed = true; } } Пишу с мобилы и без проверки, так что объясню логику (на тот случай если в коде и сам накосячил): перебирая элементы от конца к началу, мы у каждого текущего безусловно удаляем класс, и добавляем обратно только если ранее (за цикл) его не "переставляли вперед", и если предыдущий элемент есть (i > 0), и содержит класс. Таким образом, одно лишнее действие за весь цикл - это ведь гораздо лучше, чем два лишних действия на каждой его итерации. И мы яснее видим, в чем итоговые "намерения" этого участка кода, какую микрозадачу он решает. (предполагаю что читатель ответа автоматически понимает часть выражения !changed && i - при работе в команде с новичками, это можно развернуть на более императивный код с переменными. Еще лучше, когда такие вещи оформлены методами или хелпер-функциями, даже если не планируем их переиспользование)

Ответ 3



// т.е. forEach не видит элементы, по которым он еще не прошелся? Он проходится по всем эл-там и всё видит. У вас проблема в том что вы пытались к другому эл-ту массиву "достучаться" через текущий эл-т. let a = [1,2,3]; a.forEach((element, index) => { if(element == 2) { console.log(a[index + 1]); } }); Зачем вам все картинки в массиве и циклом по ним проходиться? Можно как-то так это делать: document.querySelector('.prev').addEventListener('click', function (){ let activeImg = document.querySelector('.task-12 img.active-img'), nextImg = activeImg.nextElementSibling, allImg = document.querySelectorAll('.task-12 img'); if (allImg.length > getChildNumber(activeImg)+1) { activeImg.classList.remove('active-img'); nextImg.classList.add('active-img'); } else { activeImg.classList.remove('active-img'); allImg[0].classList.add('active-img'); } }); function getChildNumber(element) { return Array.from(element.parentNode.children).indexOf(element); } .task-12 img { width: 25px; height: 25px; padding: 5px; } .active-img { border: 3px solid #000; }


Комментариев нет:

Отправить комментарий