ZhihanXing 发表于 2023-6-25 19:49:33

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

下面代码是我写的一个轮播图的效果。当页面加载后,页面的图片会每隔一秒切换成另外的图片,点击prev按钮会切换到前一张图片,点击next按钮会切换到后一张图片,点击列表中的小圆点会切换到对应的图片。但是当页面加载完毕后,立刻点击prev按钮和列表没有切换到相应的图片,第二次点击才会生效。而页面加载完成后,第一次点击next按钮,会切换到往后第二张图片而不是往后第一张图片,请问这是为什么?
<!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>轮播图点击切换</title>
    <style>
      * {
            box-sizing: border-box;
      }
      
      .slider {
            width: 560px;
            height: 400px;
            margin: 100px auto;
            overflow: hidden;
      }
      
      .slider-wrapper {
            width: 100%;
            height: 320px;
            transition: all .3s;
      }
      
      .slider-wrapper img {
            width: 100%;
            height: 100%;
            display: block;
      }
      
      .slider-footer {
            height: 80px;
            background-color: rgb(100, 67, 68);
            padding: 12px 12px 0 12px;
            position: relative;
      }
      
      .slider-footer .toggle {
            position: absolute;
            right: 0;
            top: 12px;
            /* display: flex; */
      }
      
      .slider-footer .toggle button {
            margin-right: 12px;
            width: 28px;
            height: 28px;
            /* appearance: none; */
            border: none;
            background: rgba(255, 255, 255, 0.1);
            color: #fff;
            border-radius: 4px;
            cursor: pointer;
      }
      
      .slider-footer .toggle button:hover {
            background: rgba(255, 255, 255, 0.2);
      }
      
      .slider-footer p {
            margin: 0;
            color: #fff;
            font-size: 18px;
            margin-bottom: 10px;
      }
      
      .slider-indicator {
            margin: 0;
            padding: 0;
            list-style: none;
            display: flex;
            align-items: center;
      }
      
      .slider-indicator li {
            width: 8px;
            height: 8px;
            margin: 4px;
            border-radius: 50%;
            background: #fff;
            opacity: 0.4;
            cursor: pointer;
      }
      
      .slider-indicator li.active {
            width: 12px;
            height: 12px;
            opacity: 1;
      }
    </style>
</head>

<body>
    <div class="slider">
      <div class="slider-wrapper">
            <img src="images/01.jpg" alt="" />
      </div>
      <div class="slider-footer">
            <p>aaaaaa</p>
            <ul class="slider-indicator">
                <li class="active"></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
                <li></li>
            </ul>
            <div class="toggle">
                <button class="prev">&lt;</button>
                <button class="next">&gt;</button>
            </div>
      </div>
    </div>
    <script>
      //首先创建数组对象,存入轮播图的信息
      const data = [{
            url: "images/01.jpg",
            title: "aaaaaa"
      }, {
            url: "images/02.jpg",
            title: "bbbbbb"
      }, {
            url: "images/03.jpg",
            title: "cccccc"
      }, {
            url: "images/04.jpg",
            title: "dddddd"
      }, {
            url: "images/05.jpg",
            title: "eeeeee"
      }, {
            url: "images/06.jpg",
            title: "ffffff"
      }, {
            url: "images/07.jpg",
            title: "gggggg"
      }, {
            url: "images/08.jpg",
            title: "hhhhhh"
      }, ];
      //获取需要的对象
      const img = document.querySelector('.slider-wrapper img');
      const title = document.querySelector('.slider-footer p');
      const lis = document.querySelectorAll('.slider-indicator li');
      const prev_button = document.querySelector('.toggle .prev ');
      const next_button = document.querySelector('.toggle .next ');
      let i = 0;
      //这是更改轮播图内容的函数
      function change() {
            if (i < data.length) {
                //更改图片和文字
                img.src = data.url;
                title.innerHTML = data.title;
                //更改li的样式
                for (let j = 0; j < lis.length; j++) {
                  lis.classList.remove('active');
                }
                lis.classList.add('active');
                i++;
            } else {
                i = 0;
            }
      }
      //这是两个按钮切换轮播图的函数
      function prev() {
            i -= 1;
            //保持变量i大于等于0
            if (i < 0) {
                i = data.length - 1;
            }
            // console.log("当前i的值是:" + i);
            // console.log("prev函数执行了!");
            //更改图片和文字
            img.src = data.url;
            title.innerHTML = data.title;
            //更改li的样式
            for (let j = 0; j < lis.length; j++) {
                lis.classList.remove('active');
            }
            lis.classList.add('active');
      }

      function next() {
            i += 1;
            //保持变量i大于等于0
            if (i > data.length - 1) {
                i = 0;
            }
            // console.log("当前i的值是:" + i);
            // console.log("next函数执行了!");
            //更改图片和文字
            img.src = data.url;
            title.innerHTML = data.title;
            //更改li的样式
            for (let j = 0; j < lis.length; j++) {
                lis.classList.remove('active');
            }
            lis.classList.add('active');
      }

      //这是点击li切换到对应轮播图的函数
      function lis_change() {
            for (let j = 0; j < lis.length; j++) {
                lis.addEventListener("click", function() {
                  img.src = data.url;
                  title.innerHTML = data.title;
                  for (let k = 0; k < lis.length; k++) {
                        lis.classList.remove('active');
                  }
                  lis.classList.add('active');
                  i = j;
                });
            }
      }

      //开启定时器
      let timer = setInterval(change, 1000);
      //关闭定时器的函数
      function close_timer() {
            clearInterval(timer);
      }
      //再次开启定时器的函数
      function open_timer() {
            timer = setInterval(change, 1000);
      }
      //这是两个按钮点击事件
      prev_button.addEventListener("click", prev);
      next_button.addEventListener("click", next);
      //当鼠标指针悬浮在按钮之上,关闭定时器
      prev_button.addEventListener("mouseover", close_timer);
      next_button.addEventListener("mouseover", close_timer);
      //鼠标移出按钮,重新开启定时器
      next_button.addEventListener("mouseout", open_timer);
      prev_button.addEventListener("mouseout", open_timer);
      //鼠标悬浮在li上,关闭定时器
      for (let j = 0; j < lis.length; j++) {
            lis.addEventListener("mouseover", close_timer);
      }
      //鼠标移出li,重新开启定时器
      for (let j = 0; j < lis.length; j++) {
            lis.addEventListener("mouseout", open_timer);
      }
      //鼠标点击lis事件,跳转到对应轮播图
      for (let j = 0; j < lis.length; j++) {
            lis.addEventListener("click", lis_change);
      }
    </script>
</body>

</html>

isdkz 发表于 2023-6-25 19:52:24

这个问题的根本原因在于你的定时器和按钮点击事件的冲突。定时器每隔一秒就会自动调用 change 函数,使得 i 加1;而在你点击按钮或列表项时,你也会改变 i 的值。这两个行为可能会在极短的时间内发生,从而产生你所描述的问题。

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

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

next_button.addEventListener("click", function() {
    close_timer();
    next();
    open_timer();
});

//鼠标点击lis事件,跳转到对应轮播图
for (let j = 0; j < lis.length; j++) {
    lis.addEventListener("click", function() {
      close_timer();
      i = j;
      img.src = data.url;
      title.innerHTML = data.title;
      for (let k = 0; k < lis.length; k++) {
            lis.classList.remove('active');
      }
      lis.classList.add('active');
      open_timer();
    });
}


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

function change() {
    //更改图片和文字
    img.src = data.url;
    title.innerHTML = data.title;
    //更改li的样式
    for (let j = 0; j < lis.length; j++) {
      lis.classList.remove('active');
    }
    lis.classList.add('active');
    i++;
    if (i >= data.length) {
      i = 0;
    }
}


最后,注意你在 prev 和 next 函数中直接修改了 i 的值,然后才更改了轮播图,这意味着你实际上是跳过了一张图片。你应该先更改当前的图片,然后再让 i 增加或减少。在你的 prev 和 next 函数中,去掉 i -= 1; 和 i += 1; 这两行代码,然后把它们移到函数的末尾,应该就能解决你的问题了。
页: [1]
查看完整版本: js定时器实现轮播图时,第一次点击切换按钮和列表无效