鱼C论坛

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

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

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

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

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

x
下面代码是我写的一个轮播图的效果。当页面加载后,页面的图片会每隔一秒切换成另外的图片,点击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"><</button>
                <button class="next">></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[i].url;
                title.innerHTML = data[i].title;
                //更改li的样式
                for (let j = 0; j < lis.length; j++) {
                    lis[j].classList.remove('active');
                }
                lis[i].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[i].url;
            title.innerHTML = data[i].title;
            //更改li的样式
            for (let j = 0; j < lis.length; j++) {
                lis[j].classList.remove('active');
            }
            lis[i].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[i].url;
            title.innerHTML = data[i].title;
            //更改li的样式
            for (let j = 0; j < lis.length; j++) {
                lis[j].classList.remove('active');
            }
            lis[i].classList.add('active');
        }

        //这是点击li切换到对应轮播图的函数
        function lis_change() {
            for (let j = 0; j < lis.length; j++) {
                lis[j].addEventListener("click", function() {
                    img.src = data[j].url;
                    title.innerHTML = data[j].title;
                    for (let k = 0; k < lis.length; k++) {
                        lis[k].classList.remove('active');
                    }
                    lis[j].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[j].addEventListener("mouseover", close_timer);
        }
        //鼠标移出li,重新开启定时器
        for (let j = 0; j < lis.length; j++) {
            lis[j].addEventListener("mouseout", open_timer);
        }
        //鼠标点击lis事件,跳转到对应轮播图
        for (let j = 0; j < lis.length; j++) {
            lis[j].addEventListener("click", lis_change);
        }
    </script>
</body>

</html>
最佳答案
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[j].addEventListener("click", function() {
        close_timer();
        i = j;
        img.src = data[i].url;
        title.innerHTML = data[i].title;
        for (let k = 0; k < lis.length; k++) {
            lis[k].classList.remove('active');
        }
        lis[j].classList.add('active');
        open_timer();
    });
}

另外,我发现你的 change 函数在 i 等于 data.length 时没有正确地回到0,应该调整如下:
function change() {
    //更改图片和文字
    img.src = data[i].url;
    title.innerHTML = data[i].title;
    //更改li的样式
    for (let j = 0; j < lis.length; j++) {
        lis[j].classList.remove('active');
    }
    lis[i].classList.add('active');
    i++;
    if (i >= data.length) {
        i = 0;
    }
}


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

使用道具 举报

发表于 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[j].addEventListener("click", function() {
        close_timer();
        i = j;
        img.src = data[i].url;
        title.innerHTML = data[i].title;
        for (let k = 0; k < lis.length; k++) {
            lis[k].classList.remove('active');
        }
        lis[j].classList.add('active');
        open_timer();
    });
}

另外,我发现你的 change 函数在 i 等于 data.length 时没有正确地回到0,应该调整如下:
function change() {
    //更改图片和文字
    img.src = data[i].url;
    title.innerHTML = data[i].title;
    //更改li的样式
    for (let j = 0; j < lis.length; j++) {
        lis[j].classList.remove('active');
    }
    lis[i].classList.add('active');
    i++;
    if (i >= data.length) {
        i = 0;
    }
}


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

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-12-23 17:44

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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