Reputation:
I'm learning JavaScript. And now I want to make a typical image slider that when the page loads automatically starts, and if one of 2 buttons (forward and backward) are clicked it stops the automatic slider and just goes to where we click the buttons.
But the code that I'm testing doesn't have the buttons working. I have even used jQuery attempting to make it work, but no success. I think that I have made a mess, but this is the code:
$(function() {
var slideIndex = 0;
var i;
var s = document.getElementsByClassName("slide");
var stopslider = false;
slider();
$(".change[n]").click(function(){
var slideIndex = 1;
var stopslider = true;
$( "slide1" ).removeClass( "slide" ).addClass( "1slide" );
$( "slide2" ).removeClass( "slide" ).addClass( "1slide" );
$( "slide3" ).removeClass( "slide" ).addClass( "1slide" );
$( "slide4" ).removeClass( "slide" ).addClass( "1slide" );
var s = document.getElementsByClassName("1slide");
slideslide1Index += n;
if (n > s.length) {
slideIndex = 1
}
if (n < 1) {
slideIndex = s.length
} ;
for (i = 0; i < s.length; i++) {
s[i].style.display = "none";
}
s[slideIndex-1].style.display = "block";
});
function slider() {
for (i = 0; i < s.length; i++) {
s[i].style.display = "none";
}
slideIndex++;
if (slideIndex > s.length) {
slideIndex = 1
}
s[slideIndex-1].style.display = "block";
setTimeout(slider, 4000);
if (stopslider= true) {
clearTimeout(slider);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="imagem1"><img id="slide1" class="slide" src="imagens/imagemcentral1.jpg"></a>
<a href="imagem2"><img id="slide2" class="slide" src="imagens/imagemcentral2.jpg"></a>
<a href="imagem3"><img id="slide3" class="slide" src="imagens/imagemcentral3.jpg"></a>
<a href="imagem4"><img id="slide4" class="slide" src="imagens/imagemcentral4.jpg"></a>
<button id="previous" class="change" n="-1">previous</button>
<button id="latter" class="change" n="+1">latter</button>
Upvotes: 0
Views: 866
Reputation: 3950
I had another look at my first answer and realized that may entirely not be what you're looking for.
So here I'll try to stay as true to your original code as possible.
See the comments below the code snippet for explanation.
window.onload = function() {
var slideIndex = 0;
var stopslider = false;
slider();
function change(n) {
stopslider = true;
var s = document.getElementsByClassName("slide");
slideIndex += n;
if (slideIndex > s.length) {
slideIndex = 1;
} else if (slideIndex < 1) {
slideIndex = s.length;
}
for (var i=0; i<s.length; i++) {
s[i].style.display = "none";
}
s[slideIndex-1].style.display = "block";
}
function slider() {
if (stopslider == false) {
var s = document.getElementsByClassName("slide");
for (var i=0; i<s.length; i++) {
s[i].style.display = "none";
}
slideIndex++;
if (slideIndex > s.length) {
slideIndex = 1;
}
s[slideIndex-1].style.display = "block";
setTimeout(slider, 4000);
}
}
//CLICK-HANDLERS-------------------------
document.getElementById("previous").onclick = function(){change(-1);};
document.getElementById("latter").onclick = function(){change(+1);};
};
<a class="slide" href="imagem1"><img src="https://placeimg.com/200/150/animals"></a>
<a class="slide" href="imagem2"><img src="https://placeimg.com/200/150/arch"></a>
<a class="slide" href="imagem3"><img src="https://placeimg.com/200/150/people"></a>
<a class="slide" href="imagem4"><img src="https://placeimg.com/200/150/tech"></a>
<button id="previous" class="change">previous</button>
<button id="latter" class="change">latter</button>
$(function() {
becomes window.onload = function() {
.var s = document.getElementsByClassName("slide");
. You could use it, but since you also already declare it inside one function, and you generally want to keep your global variables to a minimum (link1, link2), I chose to remove the global one.var i;
, same reason. It's better to declare them inside the for-loop.<button class="change" n="+1">
and ".change[n]"
are not something I am familiar with, in either HTML, pure JS or jQuery. I don't think it's possible (someone correct me if I'm wrong).id
s - which you already had. Using data-attributes, those id
s are not necessary.)$(".change[n]").click(function(){
to a regular function: function change(n) {
, where n
holds a value of either +1
or -1
that determines the direction of the slider.change(n)
, and send along parameter n
, either with value -1
or +1
.change(n)
, I removed var slideIndex = 1;
because this would override/interfere with the global variable var slideIndex
you had already declared at the start of the script.change(n)
, and the slide would never change. This is one of the reasons I created my first answer, to avoid global variables. If you're interested, check that one out.var
from var stopslider = true;
. The var
creates a new variable that is only visible inside the function (so not global), but in this case we do need to reference the global var stopslider
, because that is the variable that is checked inside the function slider()
to determine if the auto-slider should be stopped. $( "slide1" ).removeClass( "slide" ).addClass( "1slide" );
. I don't know what you were trying there, but it's not necessary. (Also, jQuery selectors for id
need a #
in front of the id
, so: $("#slide1")
).id
s from the slides in HTML, because they are not necessary and it can save you a lot of pain when you want to insert more slides later on. 1
from var s = document.getElementsByClassName("1slide");
, don't know what you were doing there either.class="slide"
from the <img/>
s to the <a>
s, because otherwise the images would be hidden, but the <a>
s of all images would still be visible, which is not what your want.<a>
s for the images or the slider itself, but you may have a specific purpose for them, so I'll leave them in.slideslide1Index += n;
to slideIndex += n;
, so it references the global variable.n
: if (n > s.length) {
, but you should check for slideIndex
. Remember, n
only ever has a value of either -1
or +1
. Global slideIndex
holds the value of the current slide.} else if (slideIndex < 1) {
. Because only ever one of the two clauses can be true, it inefficient to run them both each time change(n)
is called. And this also directly shows (to the programmer who reads the code) that these two clauses belong together, are part of one bigger check.} ;
, I removed it.i
inside the for-loop, so that becomes: for (var i=0; i<s.length; i++) {
(same in function slider()
).slider()
, because I removed the global var s = document.getElementsByClassName("slide");
, I had to add that line at the top of this function, just like in change(n)
.if (stopslider= true) {
to if (stopslider == true) {
.=
is already used to assign value, in programming we use ==
(double =
) to check if two values are equal to each other.timer = setTimeout(slider,4000);
, where timer
is a global var
that you set at the start of your script.setTimeout()
only runs once and after that just stops, we just need to not set it again.slider()
inside the if-clause that you used around clearTimeout()
, only changing true
to false
: if (stopslider == false) {
.setTimeout()
, the slider will still change automatically one more time after you clicked a button for the first time.)I changed the src
of your images, just so we can actually see them change.
data-
attribute:This snippet is based on the previous snippet, with a few changes.
window.onload = function() {
var slideIndex = 0;
var stopslider = false;
slider();
function slider() {
if (stopslider == false) {
var s = document.getElementsByClassName("slide");
for (var i=0; i<s.length; i++) {
s[i].style.display = "none";
}
slideIndex++;
if (slideIndex > s.length) {
slideIndex = 1;
}
s[slideIndex-1].style.display = "block";
setTimeout(slider, 4000);
}
}
//CLICK-HANDLERS-------------------------
(function() {
var c = document.getElementsByClassName("change");
for (var i=0; i<c.length; i++) {
c[i].onclick = function() {
stopslider = true;
var n = parseInt(this.getAttribute("data-n"));
var s = document.getElementsByClassName("slide");
slideIndex += n;
if (slideIndex > s.length) {
slideIndex = 1;
} else if (slideIndex < 1) {
slideIndex = s.length;
}
for (var i=0; i<s.length; i++) {
s[i].style.display = "none";
}
s[slideIndex-1].style.display = "block";
};
}
})();
};
<a class="slide" href="imagem1"><img src="https://placeimg.com/200/150/animals"></a>
<a class="slide" href="imagem2"><img src="https://placeimg.com/200/150/arch"></a>
<a class="slide" href="imagem3"><img src="https://placeimg.com/200/150/people"></a>
<a class="slide" href="imagem4"><img src="https://placeimg.com/200/150/tech"></a>
<button class="change" data-n="-1">previous</button>
<button class="change" data-n="+1">latter</button>
data-n="-1"
and data-n="+1"
to the respective buttons, and removed the id
s from the buttons as they are no longer necessary. Read about the data-* attributechange(n)
to an anonymous click-handler for the buttons.(function() { ... })();
.c[i].onclick = function() {
.var n = parseInt(this.getAttribute("data-n"));
to get the n
-value from the respective button.data-n
attribute is in text format, parseInt()
is needed to convert the text value to an integer.Upvotes: 0
Reputation: 3950
(For an answer using the OP's original code, see my second answer.)
Okay.. so I may have gone a little overboard:)
The thing is, when I just started out I did exactly the same as you did, with a bunch of variables to store the progress and current position etc.
But really, all that isn't necessary, and JavaScript is quite unique in that way because of the 'physical' DOM structure that is already present on the page and can be referenced instead of using a dedicated variable. They can in many cases function as your 'variables', and in many cases are preferred over (global) variables.
ANYWAY, so I pretty much changed your whole code, also renamed probably everything in the process, stripped out unnecessary elements like the <a>
tags. You might have a need for them, but I wanted to make the code as clean as possible so it's easier to understand:
Read the comments in the code to understand what's going on.
Ignore the CSS, it's only for styling. All the functionality is in the JS.
window.onload = function() {
function changeSlide(d, id) {
var slides = document.getElementById(id).children[0];
for (var i=0,count=slides.children.length; i<count; ++i) {
if (slides.children[i].className.indexOf("active") != -1) {var slide=slides.children[i]; break;} //store the current slide
}
if (d=="next") {
if (slides.lastElementChild.className.indexOf("active") != -1) {
slides.firstElementChild.className += " active"; //loop around and activate the first slide
} else {slide.nextElementSibling.className += " active";} //activate the next slide
} else { //prev
if (slides.firstElementChild.className.indexOf("active") != -1) {
slides.lastElementChild.className += " active"; //loop around and activate the last slide
} else {slide.previousElementSibling.className += " active";} //activate the prev slide
}
slide.className = slide.className.replace(" active",""); //deactivate the current slide
}
//AUTOMATIC LOOP------------------------------
function timer(id){setTimeout(function(){if (document.getElementById(id).className.indexOf("auto") != -1) {changeSlide("next",id); timer(id);}},4000);}
for (var i=0,s=document.getElementsByClassName("slider"),count=s.length; i<count; ++i) {timer(s[i].id);} //create a timer-loop for every slider
//EVENT-HANDLERS------------------------------
for (var i=0,s=document.getElementsByClassName("slider"),count=s.length; i<count; ++i) {
s[i].onmousedown = function(){return false;}; //otherwise sometimes the space next to the slider gets selected on navigation
//click-handlers for prev/next buttons
for (var j=0,c=s[i].children.length; j<c; ++j) {
if (s[i].children[j].className.indexOf("nav") != -1) {
s[i].children[j].onclick = function() {
var s = document.getElementById(this.parentNode.id);
if (s.className.indexOf("auto") != -1) {s.className = s.className.replace(" auto","");} //stop the automatic loop
changeSlide(this.className.split(" ")[1],this.parentNode.id); //prev/next slide ('this.className.split(" ")[1]' returns the second classname)
};
}
}
}
};
.slider {display:inline-block; position:relative; width:240px; height:135px; background:#000;}
.slider .slides {width:100%; height:100%;}
.slider .slides .slide {float:left; width:0; height:100%; background:center center/contain no-repeat; transition:width 0.5s ease 0s;}
.slider .slides .slide.active {width:100%;}
.slider .nav {position:absolute; top:0; width:15%; min-width:44px; height:100%; background:#888; opacity:0; cursor:pointer;}
.slider:hover .nav {opacity:0.3;}
.slider .nav.prev {left:0;}
.slider .nav.next {right:0;}
.slider .nav .btn {position:absolute; top:0; bottom:0; width:34px; height:34px; margin:auto 0; box-sizing:border-box; border:2px solid #ddd; border-radius:999px; background:#555; opacity:0.7; visibility:hidden;}
.slider .nav.prev .btn {left:5px;}
.slider .nav.next .btn {right:5px;}
.slider:hover .nav .btn {visibility:visible;}
.slider:hover .nav .btn:hover {border-color:#fff; opacity:1;}
.slider .nav .btn .arrow {position:absolute; top:0; bottom:0; width:0; height:0; margin:auto 0; border:10px solid transparent;}
.slider .nav.prev .btn .arrow {right:calc(50% - 3px); border-right-color:#ddd;}
.slider .nav.next .btn .arrow {left:calc(50% - 3px); border-left-color:#ddd;}
.slider .nav.prev .btn:hover .arrow {border-right-color:#fff;}
.slider .nav.next .btn:hover .arrow {border-left-color:#fff;}
<div class="slider auto" id="slider1">
<div class="slides">
<div class="slide active" style="background-image:url('https://placeimg.com/320/180/arch');"></div>
<div class="slide" style="background-image:url('https://placeimg.com/640/250/animals');"></div>
<div class="slide" style="background-image:url('https://placeimg.com/720/450/tech/sepia');"></div>
<div class="slide" style="background-image:url('https://placeimg.com/480/480/nature');"></div>
</div>
<div class="nav prev"><div class="btn"><div class="arrow"></div></div></div>
<div class="nav next"><div class="btn"><div class="arrow"></div></div></div>
</div>
<div class="slider auto" id="slider2">
<div class="slides">
<div class="slide active" style="background-image:url('https://placeimg.com/320/480/nature');"></div>
<div class="slide" style="background-image:url('https://placeimg.com/640/480/people/sepia');"></div>
<div class="slide" style="background-image:url('https://placeimg.com/640/180/tech');"></div>
<div class="slide" style="background-image:url('https://placeimg.com/640/360/arch/sepia');"></div>
</div>
<div class="nav prev"><div class="btn"><div class="arrow"></div></div></div>
<div class="nav next"><div class="btn"><div class="arrow"></div></div></div>
</div>
id
s and working only with classes.id
s that are left are on the .slider
s, I couldn't get it to work in pure JS without them.id
s at all, check out the jQuery version below.for (var i=0; i<slides.children.length; i++) {
, I declare an extra variable in the first part of the for-loop, so that the length
isn't calculated on every iteration. The result is the following for (var i=0,count=slides.children.length; i<count; ++i) {
. Using ++i
has a subtle difference over i++
, but used like this there is no practical difference.transition:width 0.5s ease 0s;
. Together with float:left;
it makes the slides really slide, instead of just static replacement.background:center center/contain no-repeat;
. This makes that the images are always nicely centered and scaled to fit the container. If the image is too wide it gets vertically centered, if it's too tall it gets horizontally centered. That's all CSS.<img/>
tags by <div>
s, and on those <div>
s set the images as background-images
.class
or an id
for that alone.$(function() {
function changeSlide(d, slides) {
var slide = $(slides).children(".slide.active")[0]; //store the current slide
if (d=="next") {
if ($(slides).children(".slide").last().hasClass("active")) {
$(slides).children(".slide").first().addClass("active"); //loop around and activate the first slide
} else {$(slide).next().addClass("active");} //activate the next slide
} else { //prev
if ($(slides).children(".slide").first().hasClass("active")) {
$(slides).children(".slide").last().addClass("active"); //loop around and activate the last slide
} else {$(slide).prev().addClass("active");} //activate the prev slide
}
$(slide).removeClass("active"); //deactivate the current slide
}
//AUTOMATIC LOOP------------------------------
function timer(slides){setTimeout(function(){if ($(slides).parent().hasClass("auto")) {changeSlide("next",slides); timer(slides);}},4000);}
$(".slider").each(function(){timer($(this).children(".slides")[0]);}); //create a timer-loop for every slider
//EVENT-HANDLERS------------------------------
$(".slider").on("mousedown",function(){return false;}); //otherwise sometimes the space next to the slider gets selected on navigation
$(".slider .nav").click(function(){
if ($(this).closest(".slider").hasClass("auto")) {$(this).closest(".slider").removeClass("auto");}; //stop the automatic loop
changeSlide(this.className.split(" ")[1],$(this).siblings(".slides")[0]); //prev/next slide
});
});
.slider {display:inline-block; position:relative; width:240px; height:135px; background:#000;}
.slider .slides {width:100%; height:100%;}
.slider .slides .slide {float:left; width:0; height:100%; background:center center/contain no-repeat; transition:width 0.5s ease 0s;}
.slider .slides .slide.active {width:100%;}
.slider .nav {position:absolute; top:0; width:15%; min-width:44px; height:100%; background:#ddd; opacity:0; cursor:pointer;}
.slider:hover .nav {opacity:0.3;}
.slider .nav.prev {left:0;}
.slider .nav.next {right:0;}
.slider .nav .btn {position:absolute; top:0; bottom:0; width:34px; height:34px; margin:auto 0; box-sizing:border-box; border:2px solid #ddd; border-radius:999px; background:#555; opacity:0.7; visibility:hidden;}
.slider .nav.prev .btn {left:5px;}
.slider .nav.next .btn {right:5px;}
.slider:hover .nav .btn {visibility:visible;}
.slider:hover .nav:hover .btn {opacity:1;}
.slider .nav .btn .arrow {position:absolute; top:0; bottom:0; width:0; height:0; margin:auto 0; border:10px solid transparent;}
.slider .nav.prev .btn .arrow {right:calc(50% - 3px); border-right-color:#ddd;}
.slider .nav.next .btn .arrow {left:calc(50% - 3px); border-left-color:#ddd;}
.slider .nav.prev:hover .btn .arrow {border-right-color:#fff;}
.slider .nav.next:hover .btn .arrow {border-left-color:#fff;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="slider auto">
<div class="slides">
<div class="slide active" style="background-image:url('https://placeimg.com/320/180/arch');"></div>
<div class="slide" style="background-image:url('https://placeimg.com/640/250/animals');"></div>
<div class="slide" style="background-image:url('https://placeimg.com/720/450/tech/sepia');"></div>
<div class="slide" style="background-image:url('https://placeimg.com/480/480/nature');"></div>
</div>
<div class="nav prev"><div class="btn"><div class="arrow"></div></div></div>
<div class="nav next"><div class="btn"><div class="arrow"></div></div></div>
</div>
<div class="slider auto">
<div class="slides">
<div class="slide active" style="background-image:url('https://placeimg.com/320/480/nature');"></div>
<div class="slide" style="background-image:url('https://placeimg.com/640/480/people/sepia');"></div>
<div class="slide" style="background-image:url('https://placeimg.com/640/180/tech');"></div>
<div class="slide" style="background-image:url('https://placeimg.com/640/360/arch/sepia');"></div>
</div>
<div class="nav prev"><div class="btn"><div class="arrow"></div></div></div>
<div class="nav next"><div class="btn"><div class="arrow"></div></div></div>
</div>
id
s, which makes it more flexible to implement on other sites.Which one you choose probably comes mostly down to preference. Personally I prefer jQuery, 'cause it just makes life so much easier and I'm already using it for everything else anyway. But when I just started out I was really suspicious of it, and coding in pure JS certainly helped me get a good understanding of what I was doing. Anyways, hope I could help, if you have any questions about the code just leave 'em in the comments and I'll try to answer them.
Upvotes: 0