//Есть массив со всеми картинками на странице
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 (<anonymous>)
at HTMLButtonElement.<anonymous> (script.js:66)
если 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');
Допущено три ошибки:
//Есть массив со всеми картинками на странице
let all_img = document.querySelectorAll('.task-12 img');
NodeList
это не массив. Различие типов важно понимать, чтобы не совершать более грубых ошибок в будущем.
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
- при работе в команде с новичками, это можно развернуть на более императивный код с переменными. Еще лучше, когда такие вещи оформлены методами или хелпер-функциями, даже если не планируем их переиспользование)
// т.е. 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;
}
<div class="task-12">
<img class="active-img" src="https://hsto.org/getpro/habr/post_images/c1a/e7e/e3d/c1ae7ee3d053f0809e9d22c320924a18.jpg" alt="">
<img src="https://hsto.org/getpro/habr/post_images/c1a/e7e/e3d/c1ae7ee3d053f0809e9d22c320924a18.jpg" alt="">
<img src="https://hsto.org/getpro/habr/post_images/c1a/e7e/e3d/c1ae7ee3d053f0809e9d22c320924a18.jpg" alt="">
<img src="https://hsto.org/getpro/habr/post_images/c1a/e7e/e3d/c1ae7ee3d053f0809e9d22c320924a18.jpg" alt="">
<img src="https://hsto.org/getpro/habr/post_images/c1a/e7e/e3d/c1ae7ee3d053f0809e9d22c320924a18.jpg" alt="">
</div>
<button class="prev">next</button>
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Я пытаюсь написать простую игру "города", и хочу что бы после того, как пользователь введет слово, оно отобразилось в div'e с id "last-word"Сейчас текст...
Я хочу реализовать такое: Я добавляю задачу(элемент с классомtaskи атрибутом data-id) через input, а потом информация сохраняется в localStorage Я код написал...
Повторял проект с coursehunter о создании блога на Nuxt + Laravel APIфронт и бэк были на разных доменах