鱼C论坛

 找回密码
 立即注册
查看: 1621|回复: 1

[已解决]js定时器实现轮播图时,第一次点击切换按钮和列表无效

[复制链接]
发表于 2023-6-25 19:49:33 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
下面代码是我写的一个轮播图的效果。当页面加载后,页面的图片会每隔一秒切换成另外的图片,点击prev按钮会切换到前一张图片,点击next按钮会切换到后一张图片,点击列表中的小圆点会切换到对应的图片。但是当页面加载完毕后,立刻点击prev按钮和列表没有切换到相应的图片,第二次点击才会生效。而页面加载完成后,第一次点击next按钮,会切换到往后第二张图片而不是往后第一张图片,请问这是为什么?
  1. <!DOCTYPE html>
  2. <html lang="en">

  3. <head>
  4.     <meta charset="UTF-8" />
  5.     <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6.     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7.     <title>轮播图点击切换</title>
  8.     <style>
  9.         * {
  10.             box-sizing: border-box;
  11.         }
  12.         
  13.         .slider {
  14.             width: 560px;
  15.             height: 400px;
  16.             margin: 100px auto;
  17.             overflow: hidden;
  18.         }
  19.         
  20.         .slider-wrapper {
  21.             width: 100%;
  22.             height: 320px;
  23.             transition: all .3s;
  24.         }
  25.         
  26.         .slider-wrapper img {
  27.             width: 100%;
  28.             height: 100%;
  29.             display: block;
  30.         }
  31.         
  32.         .slider-footer {
  33.             height: 80px;
  34.             background-color: rgb(100, 67, 68);
  35.             padding: 12px 12px 0 12px;
  36.             position: relative;
  37.         }
  38.         
  39.         .slider-footer .toggle {
  40.             position: absolute;
  41.             right: 0;
  42.             top: 12px;
  43.             /* display: flex; */
  44.         }
  45.         
  46.         .slider-footer .toggle button {
  47.             margin-right: 12px;
  48.             width: 28px;
  49.             height: 28px;
  50.             /* appearance: none; */
  51.             border: none;
  52.             background: rgba(255, 255, 255, 0.1);
  53.             color: #fff;
  54.             border-radius: 4px;
  55.             cursor: pointer;
  56.         }
  57.         
  58.         .slider-footer .toggle button:hover {
  59.             background: rgba(255, 255, 255, 0.2);
  60.         }
  61.         
  62.         .slider-footer p {
  63.             margin: 0;
  64.             color: #fff;
  65.             font-size: 18px;
  66.             margin-bottom: 10px;
  67.         }
  68.         
  69.         .slider-indicator {
  70.             margin: 0;
  71.             padding: 0;
  72.             list-style: none;
  73.             display: flex;
  74.             align-items: center;
  75.         }
  76.         
  77.         .slider-indicator li {
  78.             width: 8px;
  79.             height: 8px;
  80.             margin: 4px;
  81.             border-radius: 50%;
  82.             background: #fff;
  83.             opacity: 0.4;
  84.             cursor: pointer;
  85.         }
  86.         
  87.         .slider-indicator li.active {
  88.             width: 12px;
  89.             height: 12px;
  90.             opacity: 1;
  91.         }
  92.     </style>
  93. </head>

  94. <body>
  95.     <div class="slider">
  96.         <div class="slider-wrapper">
  97.             <img src="images/01.jpg" alt="" />
  98.         </div>
  99.         <div class="slider-footer">
  100.             <p>aaaaaa</p>
  101.             <ul class="slider-indicator">
  102.                 <li class="active"></li>
  103.                 <li></li>
  104.                 <li></li>
  105.                 <li></li>
  106.                 <li></li>
  107.                 <li></li>
  108.                 <li></li>
  109.                 <li></li>
  110.             </ul>
  111.             <div class="toggle">
  112.                 <button class="prev">&lt;</button>
  113.                 <button class="next">&gt;</button>
  114.             </div>
  115.         </div>
  116.     </div>
  117.     <script>
  118.         //首先创建数组对象,存入轮播图的信息
  119.         const data = [{
  120.             url: "images/01.jpg",
  121.             title: "aaaaaa"
  122.         }, {
  123.             url: "images/02.jpg",
  124.             title: "bbbbbb"
  125.         }, {
  126.             url: "images/03.jpg",
  127.             title: "cccccc"
  128.         }, {
  129.             url: "images/04.jpg",
  130.             title: "dddddd"
  131.         }, {
  132.             url: "images/05.jpg",
  133.             title: "eeeeee"
  134.         }, {
  135.             url: "images/06.jpg",
  136.             title: "ffffff"
  137.         }, {
  138.             url: "images/07.jpg",
  139.             title: "gggggg"
  140.         }, {
  141.             url: "images/08.jpg",
  142.             title: "hhhhhh"
  143.         }, ];
  144.         //获取需要的对象
  145.         const img = document.querySelector('.slider-wrapper img');
  146.         const title = document.querySelector('.slider-footer p');
  147.         const lis = document.querySelectorAll('.slider-indicator li');
  148.         const prev_button = document.querySelector('.toggle .prev ');
  149.         const next_button = document.querySelector('.toggle .next ');
  150.         let i = 0;
  151.         //这是更改轮播图内容的函数
  152.         function change() {
  153.             if (i < data.length) {
  154.                 //更改图片和文字
  155.                 img.src = data[i].url;
  156.                 title.innerHTML = data[i].title;
  157.                 //更改li的样式
  158.                 for (let j = 0; j < lis.length; j++) {
  159.                     lis[j].classList.remove('active');
  160.                 }
  161.                 lis[i].classList.add('active');
  162.                 i++;
  163.             } else {
  164.                 i = 0;
  165.             }
  166.         }
  167.         //这是两个按钮切换轮播图的函数
  168.         function prev() {
  169.             i -= 1;
  170.             //保持变量i大于等于0
  171.             if (i < 0) {
  172.                 i = data.length - 1;
  173.             }
  174.             // console.log("当前i的值是:" + i);
  175.             // console.log("prev函数执行了!");
  176.             //更改图片和文字
  177.             img.src = data[i].url;
  178.             title.innerHTML = data[i].title;
  179.             //更改li的样式
  180.             for (let j = 0; j < lis.length; j++) {
  181.                 lis[j].classList.remove('active');
  182.             }
  183.             lis[i].classList.add('active');
  184.         }

  185.         function next() {
  186.             i += 1;
  187.             //保持变量i大于等于0
  188.             if (i > data.length - 1) {
  189.                 i = 0;
  190.             }
  191.             // console.log("当前i的值是:" + i);
  192.             // console.log("next函数执行了!");
  193.             //更改图片和文字
  194.             img.src = data[i].url;
  195.             title.innerHTML = data[i].title;
  196.             //更改li的样式
  197.             for (let j = 0; j < lis.length; j++) {
  198.                 lis[j].classList.remove('active');
  199.             }
  200.             lis[i].classList.add('active');
  201.         }

  202.         //这是点击li切换到对应轮播图的函数
  203.         function lis_change() {
  204.             for (let j = 0; j < lis.length; j++) {
  205.                 lis[j].addEventListener("click", function() {
  206.                     img.src = data[j].url;
  207.                     title.innerHTML = data[j].title;
  208.                     for (let k = 0; k < lis.length; k++) {
  209.                         lis[k].classList.remove('active');
  210.                     }
  211.                     lis[j].classList.add('active');
  212.                     i = j;
  213.                 });
  214.             }
  215.         }

  216.         //开启定时器
  217.         let timer = setInterval(change, 1000);
  218.         //关闭定时器的函数
  219.         function close_timer() {
  220.             clearInterval(timer);
  221.         }
  222.         //再次开启定时器的函数
  223.         function open_timer() {
  224.             timer = setInterval(change, 1000);
  225.         }
  226.         //这是两个按钮点击事件
  227.         prev_button.addEventListener("click", prev);
  228.         next_button.addEventListener("click", next);
  229.         //当鼠标指针悬浮在按钮之上,关闭定时器
  230.         prev_button.addEventListener("mouseover", close_timer);
  231.         next_button.addEventListener("mouseover", close_timer);
  232.         //鼠标移出按钮,重新开启定时器
  233.         next_button.addEventListener("mouseout", open_timer);
  234.         prev_button.addEventListener("mouseout", open_timer);
  235.         //鼠标悬浮在li上,关闭定时器
  236.         for (let j = 0; j < lis.length; j++) {
  237.             lis[j].addEventListener("mouseover", close_timer);
  238.         }
  239.         //鼠标移出li,重新开启定时器
  240.         for (let j = 0; j < lis.length; j++) {
  241.             lis[j].addEventListener("mouseout", open_timer);
  242.         }
  243.         //鼠标点击lis事件,跳转到对应轮播图
  244.         for (let j = 0; j < lis.length; j++) {
  245.             lis[j].addEventListener("click", lis_change);
  246.         }
  247.     </script>
  248. </body>

  249. </html>
复制代码
最佳答案
2023-6-25 19:52:24
这个问题的根本原因在于你的定时器和按钮点击事件的冲突。定时器每隔一秒就会自动调用 change 函数,使得 i 加1;而在你点击按钮或列表项时,你也会改变 i 的值。这两个行为可能会在极短的时间内发生,从而产生你所描述的问题。

解决方案是:在点击按钮或列表项时,首先关闭定时器,然后再修改 i 的值,最后重新开启定时器。另外,你在给每个列表项绑定点击事件时出现了问题,你应该直接调用 lis_change 函数,而不是在事件处理器中调用。以下是修改后的部分代码:

  1. //这是两个按钮点击事件
  2. prev_button.addEventListener("click", function() {
  3.     close_timer();
  4.     prev();
  5.     open_timer();
  6. });

  7. next_button.addEventListener("click", function() {
  8.     close_timer();
  9.     next();
  10.     open_timer();
  11. });

  12. //鼠标点击lis事件,跳转到对应轮播图
  13. for (let j = 0; j < lis.length; j++) {
  14.     lis[j].addEventListener("click", function() {
  15.         close_timer();
  16.         i = j;
  17.         img.src = data[i].url;
  18.         title.innerHTML = data[i].title;
  19.         for (let k = 0; k < lis.length; k++) {
  20.             lis[k].classList.remove('active');
  21.         }
  22.         lis[j].classList.add('active');
  23.         open_timer();
  24.     });
  25. }
复制代码


另外,我发现你的 change 函数在 i 等于 data.length 时没有正确地回到0,应该调整如下:

  1. function change() {
  2.     //更改图片和文字
  3.     img.src = data[i].url;
  4.     title.innerHTML = data[i].title;
  5.     //更改li的样式
  6.     for (let j = 0; j < lis.length; j++) {
  7.         lis[j].classList.remove('active');
  8.     }
  9.     lis[i].classList.add('active');
  10.     i++;
  11.     if (i >= data.length) {
  12.         i = 0;
  13.     }
  14. }
复制代码


最后,注意你在 prev 和 next 函数中直接修改了 i 的值,然后才更改了轮播图,这意味着你实际上是跳过了一张图片。你应该先更改当前的图片,然后再让 i 增加或减少。在你的 prev 和 next 函数中,去掉 i -= 1; 和 i += 1; 这两行代码,然后把它们移到函数的末尾,应该就能解决你的问题了。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-6-25 19:52:24 | 显示全部楼层    本楼为最佳答案   
这个问题的根本原因在于你的定时器和按钮点击事件的冲突。定时器每隔一秒就会自动调用 change 函数,使得 i 加1;而在你点击按钮或列表项时,你也会改变 i 的值。这两个行为可能会在极短的时间内发生,从而产生你所描述的问题。

解决方案是:在点击按钮或列表项时,首先关闭定时器,然后再修改 i 的值,最后重新开启定时器。另外,你在给每个列表项绑定点击事件时出现了问题,你应该直接调用 lis_change 函数,而不是在事件处理器中调用。以下是修改后的部分代码:

  1. //这是两个按钮点击事件
  2. prev_button.addEventListener("click", function() {
  3.     close_timer();
  4.     prev();
  5.     open_timer();
  6. });

  7. next_button.addEventListener("click", function() {
  8.     close_timer();
  9.     next();
  10.     open_timer();
  11. });

  12. //鼠标点击lis事件,跳转到对应轮播图
  13. for (let j = 0; j < lis.length; j++) {
  14.     lis[j].addEventListener("click", function() {
  15.         close_timer();
  16.         i = j;
  17.         img.src = data[i].url;
  18.         title.innerHTML = data[i].title;
  19.         for (let k = 0; k < lis.length; k++) {
  20.             lis[k].classList.remove('active');
  21.         }
  22.         lis[j].classList.add('active');
  23.         open_timer();
  24.     });
  25. }
复制代码


另外,我发现你的 change 函数在 i 等于 data.length 时没有正确地回到0,应该调整如下:

  1. function change() {
  2.     //更改图片和文字
  3.     img.src = data[i].url;
  4.     title.innerHTML = data[i].title;
  5.     //更改li的样式
  6.     for (let j = 0; j < lis.length; j++) {
  7.         lis[j].classList.remove('active');
  8.     }
  9.     lis[i].classList.add('active');
  10.     i++;
  11.     if (i >= data.length) {
  12.         i = 0;
  13.     }
  14. }
复制代码


最后,注意你在 prev 和 next 函数中直接修改了 i 的值,然后才更改了轮播图,这意味着你实际上是跳过了一张图片。你应该先更改当前的图片,然后再让 i 增加或减少。在你的 prev 和 next 函数中,去掉 i -= 1; 和 i += 1; 这两行代码,然后把它们移到函数的末尾,应该就能解决你的问题了。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-9 18:15

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表