JS实现一个简单的轮播图

1,626 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

轮播图是一个常见的组件,今天用js来实现一个简单的轮播图。

功能如下:

  1. 自动轮播,有滑动效果。
  2. 左右箭头可实现上一张下一张的切换,并作了节流处理。
  3. 点击下方小圆点可切换至对应的图片。
  4. 鼠标悬停至图片或小圆点处会暂停轮播,移开则继续。

原理

轮播图原理

如上图所示 ,以展示三张图且切换下一张为例。123数字代表图1,图2,图3,蓝色矩形框为可视范围,即轮播图展示的范围,其余图片均隐藏。

  1. 状态A:页面的初始状态,默认显示第一张图片。
  2. 状态B:整个图片列表向左移动,即可显示第二张图片。
  3. 状态C:同状态B。
  4. 状态D:此时又显示第一张图片(但对于图片列表而言是最后一张),需要切换为状态E即初始状态。切换的过程需要修改整个图片列表的left值,且过渡时间设为0s。
  5. 完成了一轮循环。切换上一张同理。

源码

HTML
<div class="wrap">
    <div class="img-box">
        <img src="1.jpg" alt="" class="image">
        <img src="2.jpg" alt="" class="image">
        <img src="3.jpg" alt="" class="image">
    </div>
    <div onclick="prev()" class="btn left"><img src="left.png" alt="" class="arrow"></div>
    <div onclick="next()" class="btn right"><img src="right.png" alt="" class="arrow"></div>
    <ul>
        <li style="background-color: #333333;"></li>
        <li></li>
        <li></li>
    </ul>
</div>
JS
const imgBox = document.querySelector('.img-box')
const imgs = document.querySelectorAll('.image')
const lis = document.querySelectorAll('li')
const activeColor = '#333333'
const defaultColor = 'rgb(204, 204, 204)'
imgBox.insertBefore(imgs[imgs.length-1].cloneNode(true),imgs[0])
imgBox.appendChild(imgs[0].cloneNode(true))
imgBox.style.transform = 'translateX(-880px)'

let now = 1
let timer = null

function next(){

    //节流处理
    if(!timer){
        imgBox.style.transition = '1s'
        imgBox.style.transform = `translateX(-${++now*880}px)`

        for(let i = 0;i<imgs.length;i++){
            if(i != now-1){
                lis[i].style.backgroundColor = defaultColor
            }
        }
        if(now > imgs.length)
            lis[0].style.backgroundColor = activeColor
        else
            lis[now-1].style.backgroundColor = activeColor

        timer = setTimeout(() => {
            if(now > imgs.length){
                now = 1
                imgBox.style.transition = 'none'
                imgBox.style.transform =   `translateX(-${now*880}px)`
            }
            timer = null
        }, 1000);
    }
}

function prev(){

    if(!timer){
        imgBox.style.transition = '1s'
        imgBox.style.transform = `translateX(-${--now*880}px)`


        for(let i = 0;i<imgs.length;i++){
            if(i != now-1){
                lis[i].style.backgroundColor = defaultColor
            }
        }
        if(now == 0)
            lis[imgs.length-1].style.backgroundColor = activeColor
        else
            lis[now-1].style.backgroundColor = activeColor

        timer = setTimeout(() => {
            if(!now){
                now = imgs.length
                imgBox.style.transition = 'none'
                imgBox.style.transform =   `translateX(-${now*880}px)`
            }
            timer = null
        }, 1000);
    }
}

timerInt = setInterval(next,2000)

imgBox.onmouseover = function() {
    clearInterval(timerInt)
}
imgBox.onmouseout = function() {
    timerInt = setInterval(next,2000)
}

for(let k=0;k<imgs.length;k++){
    lis[k].onmouseover = function() {
        clearInterval(timerInt)
    }
    lis[k].onmouseout = function() {
        timerInt = setInterval(next,2000)
    }
    lis[k].onclick = function(){
        step = k + 1
        imgBox.style.transform = `translateX(-${step*880}px)`

        for(let i = 0;i<imgs.length;i++){
            if(i != k){
                lis[i].style.backgroundColor = defaultColor
            }
        }
        lis[k].style.backgroundColor = activeColor
    }
}
CSS
.wrap {
    width: 880px;
    height: 305px;
    margin: 0 auto;
    /* border: 1px solid #333333; */
    position: relative;
    overflow: hidden;
}

.img-box {
    width: 880px;
    display: flex;
    position: absolute;
}

.btn {
    position: absolute;
    z-index: 1;
    width: 50px;
    height: 305px;
    line-height: 305px;
    text-align: center;
    font-size: 16px;
    color: #ffffff;
    font-weight: bold;
    cursor: pointer;
}

.btn:hover {
    background-color: rgba(240, 240, 235, 0.575);
}

.left {
    left: 0;
}

.right {
    right: 0;
}

.arrow {
    width: 15px;
    height: 15px;
}

.wrap ul{
    padding: 0;
    list-style: none;
    width: 880px;
    height: 15px;
    margin: 0 auto;
    display: flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    bottom: 10px;
    z-index: 1;
}

.wrap ul li {
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background-color:rgb(204, 204, 204);
    margin: 0 5px;
}

实现效果

2021030515260451.gif

需要注意的地方

  • 首尾各加一张图的目的是为了初次点击时能有好的过渡效果,并且更便于背后的操作。
  • 一定要等过渡完成后才进行移动的暗箱操作,所以会使用延时器setTimeout,且时延===过渡时间。
  • 为防止用户点击速度过快,一定要进行节流处理。