简体   繁体   中英

Why does classList return an error: Uncaught TypeError: Cannot read properties of undefined (reading 'classList')?

I don't understand why I get an error: Uncaught TypeError: Cannot read properties of undefined (reading 'classList') console.log(slid[numberArray].classList) - working, but slid[numberArray].classList.add('active') - not working I know that this is not a good code, but I'm still learning and I want to make a slider myself

 const slid = [...document.querySelectorAll('.slid')]; const arrows = document.querySelectorAll('.arrows-slider .arrow'); slid.forEach(s => { if( s.classList.contains('active') == false){ s.style.opacity = '0'; } }); arrows.forEach( arrow =>{ arrow.addEventListener('click', function(){ if(this.classList.contains('arrows-right')){ slid.forEach(s => { if( s.classList.contains('active')){ s.classList.remove('active'); let numberArray = slid.indexOf(s); numberArray ++; slid[numberArray].classList.add('active'); console.log(slid[numberArray].classList); } }); }else if( this.classList.contains('arrows-left')){ } }); });
 .slider { position: absolute; top: 0; left: 0; width: 100%; background-image: url('../img/mirrored_squares.png'); height: 100vh; } .slid { position: absolute; width: 100%; height: 100vh; opacity: 0; } .active { opacity: 1 !important; } .img-slid { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 35%; height: 50%; background-size: cover; } .engine { background-image: url("../img/silnik.jpg"); } .exhaust { background-image: url("../img/wydech.jpg"); } .slid-text { position: absolute; top: 50%; left: 11%; transform: translateY(-50%); font-size: 8rem; text-transform: uppercase; color: #fff; font-family: 'Black Ops One', cursive; } .number-slaid { position: absolute; bottom: 8%; right: 8%; font-size: 2rem; color: #fff; font-family: 'Black Ops One', cursive; } /* .arrows-left { position: absolute; top: 50%; left: 5%; transform: translateY(-50%); } .line-arrow { width: 2px; height: 70px; background-color: black; } .top-line { transform: rotate(48deg) translateY(25%); } .bottom-line { transform: rotate(-48deg) translateY(-25%); } */ .arrows-left { position: absolute; top: 50%; left: 5%; transform: translateY(-50%) rotate(45deg); } .arrows-right { position: absolute; top: 50%; right: 5%; transform: translateY(-50%) rotate(-135deg); } .arrow { width: 80px; height: 80px; border-left: 2px solid #000; border-bottom: 2px solid #000; cursor: pointer; }
 <section class="slider"> <div class="slid slid1 active"> <div class="engine img-slid"> </div> <p class="slid-text">engine</p> <p class="number-slaid">01</p> </div> <div class="slid slid2 "> <div class="exhaust img-slid"></div> <p class="slid-text">exhaust</p> <p class="number-slaid">02</p> </div> <div class="arrows-slider"> <div class="arrows-left arrow"></div> <div class="arrows-right arrow"></div> </div> </section>

Firstly, it's often a bad idea to use Array.forEach() in your scenario because it will go through the entire list even if your work was completed on the first element. So I highly suggest you use a loop you can break. Because After setting the next element.classList.active , there's no need for the list to continue.

Your Second Mistake was as David explained, not resetting back to position 0 when the last element of the list is reached.

Here's a working example. I've incorporated both arrows-right and arrows-left event behavior in one code.

 const slid = [...document.querySelectorAll('.slid')]; const arrows = document.querySelectorAll('.arrows-slider .arrow'); arrows.forEach( arrow => { arrow.addEventListener('click', function(clickEvent) { var target = clickEvent.currentTarget; for(let i = 0; i < slid.length; i++) { if( slid[i].classList.contains('active')) { slid[i].classList.remove('active'); let numberArray; if(target.classList.contains("arrows-right")) { numberArray = 0; i++; } else { numberArray = slid.length - 1; i--; } if(slid[i] === undefined) slid[numberArray].classList.add('active'); else slid[i].classList.add('active'); break; } } }); });
 .slider { position: absolute; top: 0; left: 0; width: 100%; background-image: url('../img/mirrored_squares.png'); height: 100vh; } .slid { position: absolute; width: 100%; height: 100vh; opacity: 0; display: none; } .slid.active { opacity: 1; display: block; } .img-slid { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 35%; height: 50%; background-size: cover; } .engine { background-image: url("../img/silnik.jpg"); } .exhaust { background-image: url("../img/wydech.jpg"); } .slid-text { position: absolute; top: 50%; left: 11%; transform: translateY(-50%); font-size: 8rem; text-transform: uppercase; color: green; font-family: 'Black Ops One', cursive; } .number-slaid { position: absolute; bottom: 8%; right: 8%; font-size: 2rem; color: #fff; font-family: 'Black Ops One', cursive; } /* .arrows-left { position: absolute; top: 50%; left: 5%; transform: translateY(-50%); } .line-arrow { width: 2px; height: 70px; background-color: black; } .top-line { transform: rotate(48deg) translateY(25%); } .bottom-line { transform: rotate(-48deg) translateY(-25%); } */ .arrows-left { position: absolute; top: 50%; left: 5%; transform: translateY(-50%) rotate(45deg); } .arrows-right { position: absolute; top: 50%; right: 5%; transform: translateY(-50%) rotate(-135deg); } .arrow { width: 80px; height: 80px; border-left: 2px solid #000; border-bottom: 2px solid #000; cursor: pointer; }
 <section class="slider"> <div class="slid slid1 active"> <div class="engine img-slid"> </div> <p class="slid-text">engine</p> <p class="number-slaid">01</p> </div> <div class="slid slid2 "> <div class="exhaust img-slid"></div> <p class="slid-text">exhaust</p> <p class="number-slaid">02</p> </div> <div class="slid slid3 "> <div class="smoke img-slid"></div> <p class="slid-text">smoke</p> <p class="number-slaid">03</p> </div> <div class="arrows-slider"> <div class="arrows-left arrow"></div> <div class="arrows-right arrow"></div> </div> </section>

When you loop over your slid array, you define s as each element in that array:

slid.forEach(s => {

You then define numberArray as the index of that element in that array:

let numberArray = slid.indexOf(s);

Then you increment numberArray :

numberArray ++;

And then access the element at that new index:

slid[numberArray].classList.add('active');

So what will happen when s is the last element of the array? numberArray will be the index of that element, which you then increment to the index of the element after the last element . No such element exists, so at that time slid[numberArray] is undefined .

How do you want to handle it when you've reached the end of the array? However you want to handle it, that's where you'd implement that logic.

For example, if you want to start over at the beginning of the array when reaching the last element, you'd check if you're at the end of the array and reset to 0 :

let numberArray = slid.indexOf(s);
numberArray ++;
if (numberArray >= slid.length) {
  numberArray = 0;
}
slid[numberArray].classList.add('active');

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM