繁体   English   中英

JavaScript-图像滑块按钮不起作用

[英]JavaScript - Image slider buttons not working

我正在学习JavaScript。 现在,我想制作一个典型的图像滑块,当页面加载时它会自动启动,如果单击2个按钮(向前和向后)之一,它将停止自动滑块,然后转到我们单击按钮的位置。

但是我正在测试的代码没有使按钮起作用。 我什至使用jQuery尝试使其工作,但没有成功。 我认为我已经一团糟,但这是代码:

 $(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> 

(有关使用OP原始代码的答案 ,请参阅我的第二个答案 。)

好吧..所以我可能有点过头了:)

问题是,当我刚开始时,我做的和您做的完全一样,只是有一堆变量来存储进度和当前位置等。

但是实际上,所有这些都是不必要的,并且JavaScript具有这种独特性,因为页面上已经存在“物理” DOM结构,并且可以引用它,而不必使用专用变量。 在许多情况下,它们可以充当您的“变量”,并且在许多情况下,它们优于(全局)变量。

无论如何,所以我几乎更改了整个代码,还重命名了过程中的所有内容,去除了<a>标记等不必要的元素。 您可能需要它们,但我想使代码尽可能简洁,以便于理解:

阅读代码中的注释以了解发生了什么。
忽略CSS,仅用于样式设置。 所有功能都在JS中。

纯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> 
jsfiddle: https ://jsfiddle.net/9pommada/9/

  • 我这样做是为了您可以在页面上添加多个滑块,并且它们都将彼此独立地工作。 我通过删除(几乎)所有id并仅使用类来做到这一点。
    剩下的唯一id是在.slider ,没有它们我无法在纯JS中工作。
    如果您根本不需要id ,请查看下面的jQuery版本。
  • for循环对您可能看起来有些奇怪。 基本上,不是for (var i=0; i<slides.children.length; i++) {做更熟悉的版本,而是在for循环的第一部分中声明了一个额外的变量,因此length不是在每次迭代中计算。 for (var i=0,count=slides.children.length; i<count; ++i) { 使用++i i++细微的区别 ,但是像这样使用时,没有实际区别。
  • 我说过所有功能都在JS中,但这并不完全正确。 CSS中有一些东西会影响滑块的行为。 尽管这主要是花哨的过渡,但是不久前您也必须在JavaScript中进行编码,因此它绝对是我认为的功能的一部分。
    一种是transition:width 0.5s ease 0s; 连同float:left; 它使幻灯片真正滑动,而不仅仅是静态替换。
    另一个是background:center center/contain no-repeat; 这使得图像始终可以很好地居中并缩放以适合容器。 如果图像太宽,它将垂直居中;如果图像太高,它将水平居中。 就是CSS。
  • 首先可能要忽略的另一个重要点是,要使上述要点(关于图像居中和缩放)起作用,您需要将<img/>标记替换为<div> ,并在这些<div>集合上图像作为background-images
    我在这里用HTML做到了,这通常被认为是不好的作法,但是如果要将它们移到CSS,则必须为每张幻灯片单独提供一个唯一的class或一个id

JQUERY:

 $(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> 
jsfiddle: https ://jsfiddle.net/nwbx5g02/11/

  • 因为我们可以使用jQuery对象,所以我们可以消除所有id ,这使得在其他站点上实现更加灵活。

您选择的哪个可能主要取决于偏好。 我个人更喜欢jQuery,因为它使生活变得更加轻松,而且无论如何我已经将它用于其他所有功能。 但是当我刚开始的时候,我真的对此感到怀疑,使用纯JS编码当然可以帮助我更好地了解自己在做什么。 无论如何,希望对我有帮助,如果您对代码有任何疑问,请将'em留在注释中,我会尽力回答。

我再次看了我的第一个答案 ,意识到可能完全不是您想要的。
因此,在这里,我将尽量保持对您原始代码的忠诚。

有关说明,请参见代码段下方的注释。

 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> 
jsfiddle: https ://jsfiddle.net/Lkeaejkn/

  • 因为您说过最初您是用纯JS编码的,所以我将所有jQuery都还原了。
    因此$(function() {成为window.onload = function() {
  • 我删除了全局变量var s = document.getElementsByClassName("slide"); 您可以使用它,但是由于您也已经在一个函数中声明了它,并且通常希望将全局变量保持为最小值( link1link2 ),因此我选择删除全局变量。
    我也删除了var i; ,同样的原因。 最好在for循环中声明它们。
  • 在HTML,纯JS或jQuery中,我都不熟悉<button class="change" n="+1">".change[n]" 我认为这是不可能的(如果我错了,请纠正我)
    您不能仅仅组成自己的HTML属性。 好吧,可以使用data- *属性 您可以使用它们,如果需要,请查看下面的第二个代码片段。
    在此代码段中,我选择了另一种使用JS内部onclick-handlers的方法。
    (将所有HTML和JS分开是一种较好的做法,因此,此选项可能会更好。但是,对于此选项,您确实需要给按钮id s-已经拥有它。使用数据属性,则不需要这些id 。)
    在您的JS中,将$(".change[n]").click(function(){更改为常规函数: function change(n) { ,其中n保留确定方向的+1-1滑块的
    在代码的底部,我添加了两个单击处理程序,它们都调用函数change(n) ,并随参数n一起发送,值-1+1
  • 在函数change(n) ,我删除了var slideIndex = 1; 因为这会覆盖/干扰您在脚本开始时已经声明的全局变量var slideIndex
    不幸的是,该变量必须保持全局性,否则每次调用函数change(n)都将重置该值,并且幻灯片将永远不会更改。 这是我创建第一个答案以避免全局变量的原因之一。 如果你有兴趣,请那一个了。
    1. 我从var stopslider = true;删除了var var stopslider = true; var创建一个仅在函数内部可见的新变量(因此在全局内部不可见),但是在这种情况下,我们确实需要引用全局var stopslider ,因为这是在函数slider()内部检查的变量,以确定是否自动滑块应停止。
    2. 我删除了所有$( "slide1" ).removeClass( "slide" ).addClass( "1slide" ); 我不知道您在那儿尝试什么,但这不是必需的。 (此外,用于id jQuery选择器需要在id前面加# ,因此: $("#slide1") )。
      我还继续从HTML幻灯片中删除了所有id ,因为它们不是必需的,并且当您以后要插入更多幻灯片时,可以避免很多麻烦。
    3. 我还从var s = document.getElementsByClassName("1slide");删除了1 var s = document.getElementsByClassName("1slide"); ,也不知道您在那做什么。
      我也将class="slide"<img/>移到了<a> ,因为否则图像将被隐藏,但是所有图像的<a>仍然可见,这不是您想要的。
      您实际上不需要图像或滑块本身的<a> ,但是您可能有特定的用途,因此我将其保留。
    4. 我改变了slideslide1Index += n; slideIndex += n; ,因此它引用了全局变量。
  • 在所有if子句中,您都检查nif (n > s.length) { ,但是您应该检查slideIndex 请记住, n永远不会具有-1+1的值。 Global slideIndex保存当前幻灯片的值。
  • 我将两个if子句组合成if-else: } else if (slideIndex < 1) { 因为这两个子句中只有一个是真的,所以每次调用change(n)时都无法运行它们。 并且这也直接(向阅读代码的程序员显示)这两个子句在一起,是一项较大检查的一部分。
  • 您有错别字: } ; ,我将其删除。
  • 正如我之前所说的,最好在for循环中声明i ,这样就可以: for (var i=0; i<s.length; i++) { (与函数slider()相同)。
  • 在函数var s = document.getElementsByClassName("slide"); slider()内部,因为我删除了全局变量var s = document.getElementsByClassName("slide"); ,我必须在该函数的顶部添加该行,就像在change(n)
  • 在if子句条件下,我将if (stopslider= true) {更改为if (stopslider == true) {
    因为=已经用于分配值,所以在编程中我们使用== (double = )检查两个值是否相等。
  • 为了能够清除超时,不幸的是,在设置该定时器时,首先需要存储对该定时器的全局引用,因此: timer = setTimeout(slider,4000); ,其中timer是您在脚本开始时设置的全局var
    幸运的是,我们实际上不需要清除计时器。 因为setTimeout()仅运行一次,然后停止,所以我们无需再次设置它。
    为了做到这一点,只需将所有来自函数slider()的代码放入您在clearTimeout()周围使用的if子句中,只需将true更改为falseif (stopslider == false) {
    (如果仅将其放在setTimeout()周围,​​则在第一次单击按钮后,滑块仍将自动再更改一次。)

我更改了图片的src ,以便我们可以实际看到它们的更改。


使用data-属性的代码段:

此代码段基于上一个代码段,并进行了一些更改。

 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> 
jsfiddle: https ://jsfiddle.net/Lkeaejkn/2/

  • 在HTML中,我向相应的按钮添加了data-n="-1"data-n="+1" ,并从按钮中删除了id ,因为不再需要它们了。 阅读有关data- *属性的信息
  • 在JS中,我删除了旧的基于id的单击处理程序,而是将整个函数change(n)为按钮的匿名单击处理程序。
  • 我将点击处理程序包装在一个自执行的匿名函数中,以防止出现更多全局变量: (function() { ... })();
  • 然后,我使用与幻灯片相同的原理,但是现在要遍历按钮。
    然后,对于每个按钮,我绑定实际的单击处理程序: c[i].onclick = function() {
  • 在点击处理程序内部使用var n = parseInt(this.getAttribute("data-n")); 从相应按钮获取n值。
    由于data-n属性中的data-n为文本格式,因此需要parseInt()将文本值转换为整数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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