how can fixed this prve button for slide show - javascript

I want to create one slide show with Array. I created the "next" button and this works good.
I tried to fix the "prv" button but I can't. What to do? I tried imgIndex--; but its not working.
let downimgs = document.querySelectorAll('.down-imgs img')
let topimg = document.querySelector('.top-img img')
let myImg = document.getElementById('mainimge')
let imgArray = ["img/3-kid.jpeg", "img/men-1.jpg", "img/woamn-1.jpeg", "img/woman-2.jpg"]
let imgIndex = 0;
downimgs.forEach(imgs => {
imgs.addEventListener('click', () => {
topimg.src = imgs.src
})
});
function next() {
myImg.setAttribute("src", imgArray[imgIndex]);
imgIndex++;
if (imgIndex >= imgArray.length) {
imgIndex = 0
}
}
// my proplem here ..
function prv() {
myImg.setAttribute("src", imgArray[imgIndex - 1]);
imgIndex--;
if (imgIndex >= imgArray.length) {
imgIndex = 3
}
}
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
img {
height: 300px;
}
.top-img img {
width: 100%;
object-fit: cover;
position: relative;
}
.next,
.prv {
display: inline-block;
width: 150px;
height: 150px;
left: 100%;
position: absolute;
padding: 15px;
font-size: 50px;
color: red;
cursor: pointer;
}
.next {
transform: translate(-150px, -50px);
}
.prv {
left: 0;
transform: translate(150px, -50px);
}
.down-imgs img {
width: 150px;
height: 150px;
}
.full-parent {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="s.css">
</head>
<body>
<section class="full-parent">
<figure class="top-img">
<img src="img/3-kid.jpeg" alt="" id="mainimge">
</figure>
<div class="down-imgs">
<img src="img/3-kid.jpeg" class="slide">
<img src="img/men-1.jpg" alt="" class="slide">
<img src="img/woamn-1.jpeg" alt="" class="slide">
<img src="img/woman-2.jpg" alt="" class="slide">
</div>
<span class="next" onclick="next()">&#10095</span>
<span class="prv" onclick="prv()">&#10094</span>
</section>
<script src="s.js"></script>
</body>
</html>

There is a defect in your prv function. You are decrementing imgIndex, but then checking that imgIndex is greater than or equal to the array length. Instead, you want to check that imgIndex is less than 0, then adjust accordingly. You will also want to change the order of the boundary check, otherwise you have potential to go out of bounds with imgArray[imgIndex-1].
Based on your code, I believe you want something like:
function prv(){
if (--imgIndex<0){ // if imgIndex leaves imgArray lower bound
imgIndex = imgArray.length-1; // wrap imgIndex around to the upper bound of the array
}
myImg.setAttribute("src" , imgArray[imgIndex]);
}

Related

Why my loading text not stand out tho it has bigger z-index than my background image?

I'm making a blurry loading effect. My background image has a z-index of -1 and my loading text has no z-index. Everything works except my loading text, I can't see it loading and stand out from my background image...
Does anybody know what's wrong? it'd be kind of you to help! Thank you so much!
This is my JS:
const loadText = document.querySelector('.loading-text')
const bg = document.querySelector('.bg')
let load = 0
let int = setInterval(blurring, 30)
const scale = (num, in_min, in_max, out_min, out_max) => {
return ((num - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min
}
function blurring() {
load++
if (load > 99) {
clearInterval(int)
}
loadText.innerText = `${load}%`
loadText.style.opacity = scale(load, 0, 100, 1, 0)
bg.style.filter = `blur(${scale(load, 0, 100, 30, 0)}px)`
}
This is my html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blurry Loading</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<section class="bg">
<div class="loading-text">
0%
</div>
</section>
<script src="script.js"></script>
</body>
</html>
This is my CSS:
* {
box-sizing: border-box;
}
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
overflow: hidden;
margin: 0;
}
.bg {
background: url('z.jpg') no-repeat center center/cover;
position: absolute;
top: -30px;
left: -30px;
width: calc(100vw + 60px);
height: calc(100vw + 60px);
z-index: -1;
filter: blur(0px)
}
.loading-text {
padding: 50% 50%;
font-size: 50px;
color: #fff;
It's actually visible, but very poorly because you're putting blur filter on bg element and everything inside (that includes your loading-text). Just put your loading-text outside.
This problem is occurring because loading-text is inside bg. So when the blur effect is applied to bg it automatically gets applied to loading-text as well. So the loading percentage is being rendered, but it's blurred into the background image and therefore not visible.
One solution is to have two elements within your bg element. These elements would not be nested and therefore any style applied to either element would not affect the other element. The first element would show the background image and the second element would show the loading text.
Here is a way to do that using your code, but I've removed anything that isn't necessary to achieve this effect:
const loadText = document.querySelector('.loading-text')
const bg = document.querySelector('.bg-image')
let load = 0
let int = setInterval(blurring, 30)
const scale = (num, in_min, in_max, out_min, out_max) => {
return ((num - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min
}
function blurring() {
load++
if (load > 99) {
clearInterval(int)
}
loadText.innerText = `${load}%`
loadText.style.opacity = scale(load, 0, 100, 1, 0)
bg.style.filter = `blur(${scale(load, 0, 100, 30, 0)}px)`
}
.bg,
.bg-image {
position: absolute;
top: 0;
left: 0;
width: 200px;
height: 190px;
}
.bg-image {
background-image: url('https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/FullMoon2010.jpg/200px-FullMoon2010.jpg');
filter: blur(30px);
}
.loading-text {
color: #fff;
font: normal 32px serif;
text-align: center;
line-height: 190px;
}
<!DOCTYPE html>
<html lang="en">
<body>
<section class="bg">
<div class="bg-image">
</div>
<div class="loading-text">
0%
</div>
</section>
</body>
</html>

How can i go to the next/previous image lightbox using ev.target.nextElementSibling ev.targetprevElementSibling?

I am beginner to web development
I have a problem with my lightbox, i need to use ev.target.nextElementSibling and ev.target.prevElementSibling to go to the next/previous image by clicking at the next arrow.png (img)/ prev arrow.png(img), i have tried everything but i don't know how. When i'm clicking at the image it's zoom in (that's ok) but when i click on the arrow the image is hidding but i want to go to the next/prev image.
const imgs = document.querySelectorAll('.gallery img');
const lightbox = document.querySelector('.lightbox');
const arrowNext = document.querySelector('.arrowNext');
for (let index = 0; index < imgs.length; index++) {
const img = imgs[index];
img.addEventListener('click', showLightbox);
}
function showLightbox(ev) {
const prevEl = ev.target.prevElementSibling;
const nextEl = ev.target.nextElementSibling;
console.log(ev)
const lightbox = document.querySelector('.lightbox');
const img = document.querySelector('.lightbox img');
const imgUrl = ev.target.src;
img.src = imgUrl;
lightbox.classList.add('visible');
}
lightbox.addEventListener('click', hideLightbox);
function hideLightbox() {
lightbox.classList.remove('visible');
}
arrowNext.addEventListener('click', nextPhoto);
function nextPhoto(ev) {
const arrowNext = document.querySelector('.arrowNext');
const img = document.querySelector('.arrowNext img');
const imgUrl = ev.target.src;
img.src = imgUrl;
const next = ev.target.nextElementSibling;
}
body {
background: #eee;
}
.lightbox {
position: absolute;
z-index: 100;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
top: 0;
left: 0;
justify-content: center;
align-items: center;
display: flex;
transition: all 0.5s cubic-bezier(0.075, 0.82, 0.165, 1);
transform: scale(0);
}
.visible {
transform: scale(1);
}
.lightbox img {
max-width: 80%;
max-height: 80%;
}
.arrowNext {
cursor: pointer;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lightbox</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<section class="gallery">
<img src="/img/img1.jpg" alt="photo1">
<img src="/img/img2.jpg" alt="photo2">
<img src="/img/img3.jpg" alt="photo3">
<img src="/img/img4.jpg" alt="photo4">
</section>
<div class="lightbox">
<div class="arrowPrev">
<img src="/img/prev arrow.png" alt="">
</div>
<img src="/img/img5.jp" alt="">
<div class="arrowNext">
<img src="/img/next arrow.png" alt="">
</div>
</div>
<script src="main.js" type="text/javascript"></script>
</body>
</html>
Be aware that ev.target is the the element the mouse clicks on, in your case the arrow. You're looking to get the next image, not the next arrow.
I'd advise using an index variable to get which image is presented and then doing document.querySelectorAll('img')[index+1] to get the next image.
With what your code could give:
(Be aware that ev.stopPropagation() is needed to prevent closing the lightbox when the arrow is clicked.)
const imgs = document.querySelectorAll('.gallery img');
const lightbox = document.querySelector('.lightbox');
const arrowNext = document.querySelector('.arrowNext');
var index = 0;
for (let index = 0; index < imgs.length; index++) {
const img = imgs[index];
img.addEventListener('click', (e) => {showLightbox(e, index)});
}
function showLightbox(ev, i) {
const prevEl = ev.target.prevElementSibling;
const nextEl = ev.target.nextElementSibling;
const lightbox = document.querySelector('.lightbox');
const img = document.querySelector('.lightbox img');
const imgUrl = ev.target.src;
img.src = imgUrl;
index = i;
lightbox.classList.add('visible');
}
lightbox.addEventListener('click', hideLightbox);
function hideLightbox() {
lightbox.classList.remove('visible');
}
arrowNext.addEventListener('click', nextPhoto);
function nextPhoto(ev) {
ev.stopPropagation();
index++;
const arrowNext = document.querySelector('.arrowNext');
const img = document.querySelector('.arrowNext img');
const imgUrl = imgs[index].src;
img.src = imgUrl;
}
body {
background: #eee;
}
.lightbox {
position: absolute;
z-index: 100;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
top: 0;
left: 0;
justify-content: center;
align-items: center;
display: flex;
transition: all 0.5s cubic-bezier(0.075, 0.82, 0.165, 1);
transform: scale(0);
}
.visible {
transform: scale(1);
}
.lightbox img {
max-width: 80%;
max-height: 80%;
}
.arrowNext {
cursor: pointer;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lightbox</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<section class="gallery">
<img src="/img/img1.jpg" alt="photo1">
<img src="/img/img2.jpg" alt="photo2">
<img src="/img/img3.jpg" alt="photo3">
<img src="/img/img4.jpg" alt="photo4">
</section>
<div class="lightbox">
<div class="arrowPrev">
<img src="/img/prev arrow.png" alt="">
</div>
<img src="/img/img5.jp" alt="">
<div class="arrowNext">
<img src="/img/next arrow.png" alt="" style="background:red;padding:20px">
</div>
</div>
<script src="main.js" type="text/javascript"></script>
</body>
</html>

why don't my javascript marquee move smoothly?

I have created a marquee using javascript. It will move from right to left of the screen displaying a number of images. The images don't move smoothly like in a marquee but jerks as if in an automated slide slow.
const slideContainer = document.querySelector('.container');
const slide = document.querySelector('.slides');
const interval = 1000;
let slides = document.querySelectorAll('.slide');
let index = 1;
const firstClone = slides[0].cloneNode(true);
const lastClone = slides[slides.length-1].cloneNode(true);
firstClone.id = 'first-clone';
lastClone.id = 'last-clone';
slide.append(firstClone);
slide.prepend(lastClone);
const slidewidth = slides[index].clientWidth;
slide.style.transform = `translateX(${-slidewidth * index}px, 0)`;
slide.style.transition = `.7s`;
const startSlide = ()=>{
setInterval(() => {
index++;
slide.style.transform = `translateX(${-slidewidth * index}px)`;
slide.style.transition = `.7s`;
}, interval);
};
slide.addEventListener('transitionend', ()=>{
slides = document.querySelectorAll('.slide');
console.log(index);
if (slides[index].id===firstClone.id) {
slide.style.transition = `none`;
index = 1;
slide.style.transform = `translateX(${-slidewidth * index}px)`;
}
});
startSlide();
.{
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container{
margin: 0 auto;
width:40vw;
height: 85vh;
border: 2px solid #8e6c5e;
border-radius: 10px;
position: relative;
overflow: hidden;
}
.container.hide{
display: none;
}
.slides{
display: flex;
height: 100%;
}
.slide{
/*object-fit: contain;*/
min-width: 100%
}
.slide img{
width: 100%;
height: 100%;
display: flex;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>cards of fate</title>
</head>
<body>
<div class="container">
<div class="slides">
<div class="slide">
<img src="https://cdn.pixabay.com/photo/2015/05/09/07/31/virgin-759376_960_720.jpg" alt="">
</div>
<div class="slide">
<img src="https://cdn.pixabay.com/photo/2015/05/09/07/32/bull-759381_960_720.jpg" alt="">
</div>
<div class="slide">
<img src="https://cdn.pixabay.com/photo/2015/05/09/07/30/twins-759375_960_720.jpg" alt="">
</div>
<div class="slide">
<img src="https://cdn.pixabay.com/photo/2015/05/09/07/30/lion-759374_960_720.jpg" alt="">
</div>
</div>
</div>
<script src="main_v1.js"></script>
</body>
</html>
I tried playing around the transition interval and speed but to no avail. I am little new around this so please help me out

JS Script position in HTML

I'm trying to create a simple app with HTMl, CSS and vanilla JS.
I've got an array, and ant to display its items in a box, with a button below it that gets the average of the array, which should also appear below the button.
So far, the layout has been very difficult, as I'm familiar with core JS and basic HTML, but never worked with scripts before. I can't make the button to be displayed below the array items and in the centre, no matter what I do. For it to appear after the array, I've applied flex box to the body, because I don't know how to create a wrapping html element, although I've seen some threads, don't know how to implement it.
Is there an easy way (avoiding JQuery) of doing this? Can't I just create a wrapping the script?
This is my code so far:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="style.css">
<title>Test</title>
</head>
<body onload="mapping()">
<script>
const array = [2, 3, 4, 5];
function mapping() {
array.map(arrayItem => {
let elements = document.createElement('p');
elements.innerHTML = arrayItem;
document.body.appendChild(elements);
elements.classList.add("numbers");
});
}
</script>
<div class='container'>
<div class='button'>
<p>
<button onClick="average()">Average</button>
</p>
</div>
<div id='val'></div>
</div>
<script>
function average() {
const array = [2, 3, 4, 5]
let count = 0
let val = array.reduce((x, y) => {
if (+y) {
count++
x += +y
}
return x
}, 0)
val = val / count;
document.getElementById('val').innerHTML += val + '<br/>';
}
</script>
</body>
</html>
body {
display: flex;
flex-direction: row-reverse;
justify-content: space-around;
align-items: center;
/* flex-wrap: wrap; */
}
.numbers {
font-size: 5em;
/* color: blue; */
/* text-orientation: unset; */
margin-top: 2em;
}
.button {
padding: 1em;
border: .2em solid red;
margin-top: 20em;
position: inherit;
}
Sorry I'm very junior and can't figure out how to do it.
I'm struggling to fully understand where the issue is, I've gone and made a jsfiddle that I think does what you're interested in.
I have a feeling the problem is the fact that you use display: flex; on the body of the document. I've surrounded the numbers in a separate div element that now has the flex-display options assigned to it.
HTML
const array = [2, 3, 4, 5];
function mapping() {
array.map(arrayItem => {
let elements = document.createElement('p');
elements.innerHTML = arrayItem;
/*
Adding the numbers to the elNumberArray div element in the HTML
*/
document.getElementById("elNumberArray").appendChild(elements);
elements.classList.add("numbers");
});
document.getElementById("elAverageButton").addEventListener("click", average);
}
function average() {
const array = [2, 3, 4, 5]
let count = 0
let val = array.reduce((x, y) => {
if (+y) {
count++
x += +y
}
return x
}, 0)
val = val / count;
document.getElementById('val').innerHTML += val + '<br/>';
}
document.onload = mapping();
body {}
/* display-flex settings are now no longer on the whole body
but set for elNumberArray div element */
#elNumberArray {
display: flex;
flex-direction: row-reverse;
justify-content: space-around;
align-items: center;
/* flex-wrap: wrap; */
}
.numbers {
font-size: 5em;
/* color: blue; */
/* text-orientation: unset; */
margin-top: 2em;
}
.button {
padding: 1em;
border: .2em solid red;
margin-top: 20em;
position: inherit;
}
<div id="elNumberArray">
<!--Numbers are now inserted here-->
</div>
<div class='container'>
<div class='button'>
<p>
<button id="elAverageButton">Average</button>
</p>
</div>
<div id='val'></div>
</div>
The button and average are now displayed below the numbers.
Is this what you were looking for?
You should place the array contents inside span tags instead of p tags.
body {
display: flex;
align-items: center;
/* flex-wrap: wrap; */
}
.numbers {
font-size: 5em;
}
.button {
padding: 1em;
border: .2em solid red;
margin-top: 20em;
}
.container{
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="style.css">
<title>Test</title>
</head>
<body onload="mapping()">
<script>
const array = [2, 3, 4, 5];
function mapping() {
array.map(arrayItem => {
let elements = document.createElement('span');
elements.innerHTML = arrayItem;
document.getElementById("numbers").appendChild(elements);
elements.classList.add("numbers");
});
}
</script>
<span id="numbers" style="margin: 20px;">
</span>
<div class='container'>
<div class='button'>
<p>
<button onClick="average()">Average</button>
</p>
</div>
<div id='val'></div>
</div>
<script>
function average() {
const array = [2, 3, 4, 5]
let count = 0
let val = array.reduce((x, y) => {
if (+y) {
count++
x += +y
}
return x
}, 0)
val = val / count;
document.getElementById('val').innerHTML += val + '<br/>';
}
</script>
</body>
</html>
JSFiddle: http://jsfiddle.net/kru10xgd/11/
const array = [2, 3, 4, 5];
let arrayContainer = document.getElementById('arrayContainer');
(function mapping() {
array.map(arrayItem => {
let element = document.createElement('p');
element.innerHTML = arrayItem;
element.classList.add("numbers");
arrayContainer.appendChild(element);
});
})();
function average() {
let count = 0
let val = array.reduce((x, y) => {
if (+y) {
count++
x += +y
}
return x
}, 0)
val = val / count;
document.getElementById('val').innerHTML += val + '<br/>';
}
.container {
width: 50%;
margin: 0 auto;
text-align: center;
transform: translate(-50%, -50%);
position: absolute;
top: 50%;
left: 50%;
}
#arrayContainer {
display: flex;
justify-content: space-evenly;
border: 1px solid;
}
.numbers {
min-width: 20px;
}
.button {
margin: 20px 0px;
}
<div class='container'>
<div id="arrayContainer"></div>
<div class='button'>
<button onClick="average()">Average</button>
</div>
<div id='val'></div>
</div>
Something like this maybe , you are trying to achieve?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<!-- // <link rel="stylesheet" href="style.css"> -->
<title>Test</title>
<style>
.container{
width: 50%;
margin: 0 auto;
text-align: center;
transform: translate(-50%,-50%);
position: absolute;
top: 50%;
left: 50%;
}
#arrayContainer{
display: flex;
justify-content: space-evenly;
border: 1px solid;
}
.numbers {
min-width: 20px;
}
.button {
margin: 20px 0px;
}
</style>
</head>
<body>
<div class='container'>
<div id="arrayContainer"></div>
<div class='button'>
<button onClick="average()">Average</button>
</div>
<div id='val'></div>
</div>
<script>
const array = [2, 3, 4, 5];
let arrayContainer = document.getElementById('arrayContainer');
(function mapping() {
array.map(arrayItem => {
let element = document.createElement('p');
element.innerHTML = arrayItem;
element.classList.add("numbers");
arrayContainer.appendChild(element);
});
})();
function average() {
let count = 0
let val = array.reduce((x, y) => {
if (+y) {
count++
x += +y
}
return x
}, 0)
val = val / count;
document.getElementById('val').innerHTML += val + '<br/>';
}
</script>
</body>
</html>

How to target different element that has same index with pure javascript [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I want to make a simple slider using pure javascript that support at least ie8, but got stuck at the moment. The problem is I when I click one of the paging items it should grab current index and then target another div for the slider container item with the same index as the paging. Basically I want to add and remove active class on both div.sliderItems & div.pagingItems based on div.pagingItems index. Here's my code:
window.onload = function(){
var slider = document.getElementById('slider'),
sliderItems = slider.children,
totalItems = sliderItems.length,
activeSlider = document.querySelector('.activeSlider'),
pagingSlider = document.getElementById('pagingSlider'),
pagingItems = pagingSlider.children,
activePaging = document.querySelector('.activePaging');
function next(){
for (var i = 0; i < totalItems; i++) {
if (i < totalItems - 1) {
if (sliderItems[i].className.match( /(?:^|\s)activeSlider(?!\S)/ )) {
sliderItems[i].className = sliderItems[i].className.replace( /(?:^|\s)activeSlider(?!\S)/g , '' );
sliderItems[i + 1].className += ' activeSlider';
pagingItems[i].className = pagingItems[i].className.replace( /(?:^|\s)activePaging(?!\S)/g , '' );
pagingItems[i + 1].className += ' activePaging';
return;
}
} else {
sliderItems[i].className = sliderItems[i].className.replace( /(?:^|\s)activeSlider(?!\S)/g , '' );
sliderItems[i + 1 - totalItems].className += ' activeSlider';
pagingItems[i].className = pagingItems[i].className.replace( /(?:^|\s)activePaging(?!\S)/g , '' );
pagingItems[i + 1 - totalItems].className += ' activePaging';
return;
}
}
}
for (var i = 0; i < totalItems; i++) {
(function(index){
pagingItems[i].onclick = function(){
pagingItems[i].className = pagingItems[i].className.replace( /(?:^|\s)activePaging(?!\S)/g , '' );
this.className += ' activePaging';
console.log(index);
}
})(i);
}
if (activeSlider === null) {
sliderItems[0].className += ' activeSlider';
pagingItems[0].className += ' activePaging';
}
var start = setInterval(next, 3000);
pagingSlider.onmouseenter = function(){clearInterval(start);};
pagingSlider.onmouseleave = function(){start = setInterval(next, 3000);};
}
* {
box-sizing: border-box;
}
html, body {
padding: 0;
margin: 0;
font-family: sans-serif;
}
.wrapperSlider {
position: relative;
width: 100%;
padding-bottom: 35%;
}
#slider {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#slider > * {
display: table;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-align: center;
color: #fff;
background: red;
opacity: 0;
transition: all ease-in-out .5s;
}
#slider > * > * {
display: table-cell;
vertical-align: middle;
}
#slider > *.activeSlider {
z-index: 1;
background: green;
opacity: 1;
}
.wrapperPaging {
text-align: center;
}
#pagingSlider {
display: inline-block;
font-size: 0;
}
#pagingSlider > * {
display: inline-block;
margin: 0 10px;
font-size: 14px;
color: black;
cursor: pointer;
transition: all ease-in-out .5s;
}
#pagingSlider > *.activePaging {
color: red;
cursor: default;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test File | Vanilla JS</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
</head>
<body>
<div class="wrapperSlider">
<div id="slider">
<div class="sliderItems">
<div>Item 1</div>
</div>
<div class="sliderItems">
<div>Item 2</div>
</div>
<div class="sliderItems">
<div>Item 3</div>
</div>
<div class="sliderItems">
<div>Item 4</div>
</div>
<div class="sliderItems">
<div>Item 5</div>
</div>
</div>
</div>
<div class="wrapperPaging">
<div id="pagingSlider">
<a class="pagingItems">1</a>
<a class="pagingItems">2</a>
<a class="pagingItems">3</a>
<a class="pagingItems">4</a>
<a class="pagingItems">5</a>
</div>
</div>
</body>
</html>
Your onclick function has a closure around the i loop counter, which is causing the "classic" closure bug of all of your event handlers sharing the same value for i and i persisting after its defining scope has ended. At that point, i has the last value set by the loop, which is one more than the number of actual items there are, so when the time comes to click on your slider, no matter which number you click on, you get the same i value that is one more than the highest index used. While your code was set up to avoid this problem by using an immediately invoked function expression that passes itself a copy of i, which it receives as index, your nested onclick functions ignored that and used i anyway. You could just change references to i with index. But, changing the pageSlider[i] reference to this solves the issue as well and doesn't rely on the IIFE.
A couple of other small pieces of advice...
An <a> is only valid when it has a name or href attribute and, in your case, you really aren't trying to navigate anywhere, so the <a> tag is inappropriate for what you are doing. In my example below, I've changed those to <span> elements, which is more appropriate.
Instead of working with the className property, it is simpler (and less error prone) to use classList, which provides .add(), remove() and toggle() and methods. When you use .add(), you don't have to worry about prepending a space in situations when there will be more than one class applied. And, most importantly, you can easily remove a class without regular expressions and String.replace().
window.onload = function(){
var slider = document.getElementById('slider'),
sliderItems = slider.children,
totalItems = sliderItems.length,
activeSlider = document.querySelector('.activeSlider'),
pagingSlider = document.getElementById('pagingSlider'),
pagingItems = pagingSlider.children,
activePaging = document.querySelector('.activePaging');
function next(){
for (var i = 0; i < totalItems; i++) {
if (i < totalItems - 1) {
if (sliderItems[i].className.indexOf('activeSlider') > -1) {
sliderItems[i].classList.remove('activeSlider');
sliderItems[i + 1].classList.add('activeSlider');
pagingItems[i].classList.remove('activePaging');
pagingItems[i + 1].classList.add('activePaging');
}
} else {
sliderItems[i].classList.remove('activeSlider');
sliderItems[i + 1 - totalItems].classList.add('activeSlider');
pagingItems[i].classList.remove('activePaging');
pagingItems[i + 1 - totalItems].classList.add('activePaging');
}
}
}
for (var i = 0; i < totalItems; i++) {
pagingItems[i].onclick = function(){
// You were forming a closure around i in this function. You can reference
// the element that triggered the event simply with "this"
this.previousElementSibling.classList.remove('activePaging');
this.classList.add('activePaging');
}
}
if (activeSlider === null) {
sliderItems[0].classList.add('activeSlider');
pagingItems[0].classList.add('activePaging');
}
var start = setInterval(next, 3000);
pagingSlider.onmouseenter = function(){clearInterval(start);};
pagingSlider.onmouseleave = function(){start = setInterval(next, 3000);};
}
* {
box-sizing: border-box;
}
html, body {
padding: 0;
margin: 0;
font-family: sans-serif;
}
.wrapperSlider {
position: relative;
width: 100%;
padding-bottom: 35%;
}
#slider {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#slider > * {
display: table;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-align: center;
color: #fff;
background: red;
opacity: 0;
transition: all ease-in-out .5s;
}
#slider > * > * {
display: table-cell;
vertical-align: middle;
}
#slider > *.activeSlider {
z-index: 1;
background: green;
opacity: 1;
}
.wrapperPaging {
text-align: center;
}
#pagingSlider {
display: inline-block;
font-size: 0;
}
#pagingSlider > * {
display: inline-block;
margin: 0 10px;
font-size: 14px;
color: black;
cursor: pointer;
transition: all ease-in-out .5s;
}
#pagingSlider > *.activePaging {
color: red;
cursor: default;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test File | Vanilla JS</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
</head>
<body>
<div class="wrapperSlider">
<div id="slider">
<div class="sliderItems">
<div>Item 1</div>
</div>
<div class="sliderItems">
<div>Item 2</div>
</div>
<div class="sliderItems">
<div>Item 3</div>
</div>
<div class="sliderItems">
<div>Item 4</div>
</div>
<div class="sliderItems">
<div>Item 5</div>
</div>
</div>
</div>
<div class="wrapperPaging">
<div id="pagingSlider">
<span class="pagingItems">1</span>
<span class="pagingItems">2</span>
<span class="pagingItems">3</span>
<span class="pagingItems">4</span>
<span class="pagingItems">5</span>
</div>
</div>
</body>
</html>

Categories

Resources