js实现轮播图

2,061 阅读5分钟

原生js实现轮播图

先来看看效果图。

Snipaste_2023-04-02_00-55-38.png 样式就没过多写,知道是什么就行了,随时都可以改的。
移动方式是css属性里的transform:translate(),然后用setTimeout这个定时器来实现的。
有一下几个效果:

  1. 自动轮播。
  2. 移入/移出暂停/开始轮播.
  3. 点击左右按钮进行切换。
  4. 点击小点点进行切换。 我的思路是假如有5张图片,最后一张在第一位,展示区域展示第二个图片。
    就是说现在是5 1 2 3 4的顺序,显示的是1那一个图片。给个思路图吧。

图一是向左。图二向右

图一

无标题.png 图二

无标题2.png 下面先来看一看CSS和HTML代码吧,

HTML

    <div id="app">
        <!--  左右按钮-->
        <div id="left" class="left arrowhead">
            <div></div>
        </div>
        <div id="right" class="right arrowhead">
            <div></div>
        </div>
        <!--  切换小点点-->
        <ul class="subscript">
        </ul>
        <!-- 切换内容-->
        <div class="content">
        </div>
    </div>

代码里没图片?
等会在js里加。

CSS

        html,
        body {
            width: 100%;
            height: 100%;
            background: pink;
        }

        ul,
        li {
            padding: 0;
            margin: 0;
        }

        /*主盒子*/
        #app {
            width: 700px;
            height: 400px;
            overflow: hidden;
            background: red;
            margin: 0 auto;
            position: relative;
        }

        /*左右按钮*/
        .left {
            margin-left: 20px;
        }

        .right {
            right: 0;
            margin-right: 20px;
        }

        .arrowhead {
            height: 100%;
            display: flex;
            align-items: center;
            position: absolute;
            z-index: 2;
            font-weight: 700;
        }

        .arrowhead div {
            border-radius: 50%;
            background: #eee;
            padding: 10px;
        }

        /*轮播内容*/
        .content {
            height: 100%;
            text-align: center;
            line-height: 400px;
            display: flex;
            position: absolute;
            left: -700px;
        }

        /*轮播图*/
        img {
            width: 700px;
            height: 100%;
        }

        /*轮播小点点*/
        .subscript {
            width: 100%;
            height: 10px;
            position: absolute;
            bottom: 0;
            z-index: 2;
            box-sizing: border-box;
            padding: 10px;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        .subscript li {
            width: 10px;
            height: 10px;
            border-radius: 50%;
            background: pink;
            list-style: none;
            margin: 0 5px 0 5px;
        }
        /*小点点当前位置的样式*/
        .subscript .active {
            background: red;
        }

现在改有的样式都有了,觉得不好看的话可以自行添加。
现在就是重点js部分了.

获取dom

首先就是获取dom.

    let left = document.getElementById('left')//左 
    let right = document.getElementById('right')//右 
    let app = document.getElementById('app')//主盒子
    let content = document.getElementsByClassName('content')[0]//内容区域
    let subscript = document.getElementsByClassName('subscript')[0]//小点点

只需要获取五个盒子就行。

创建图片并插入

创建图片数组,任意数量的图片,计算content盒子的宽,并且将图片放入到content里去。再循环出小点点,再分别给content和subscript的子元素添加上标记。然后将第一个小点点加上样式。

//创建图片数组
    let imgs = [
    "图片路径自行添加",
    "图片路径自行添加",
    "图片路径自行添加",
    "图片路径自行添加",
    ...
    ]
    //计算滚动盒子宽度
    content.style.width = `${(imgs.length) * 700}px`
    //创建图片dom
    const str = imgs.map(img => `<img src="${img}" />`).join('');
    //创建小点点dom
    const str2 = imgs.map(() => '<li class="list"></li>').join('');
    //插入父盒子和小点点
    content.innerHTML = str;
    subscript.innerHTML = str2;

    //给小点点添加下标
    for (let i = 0; i < subscript.children.length; i++) {
        subscript.children[i].setAttribute('index', i)
    }
    //给content子元素添加下标
    for (let i = 0; i < content.children.length; i++) {
        content.children[i].setAttribute('index', i)
    }
    
    //个第一个添加上样式
    subscript.children[0].classList.add('active')

定义变量

定义三个变量来控制轮播图,分别是定时器,方向和自动循环的开关。

    // 定义一个变量用来存储定时器
    let time = null;
    // 定义一个变量用来存储轮播方向
    let direction = 'left'
    //定义一个变量用来存储开关
    let flag = false
    //延迟变量
    let delay=1000

轮播相关的函数

我定义了三个函数,

  1. 第一个会有一个参数,参数是时间/毫秒,调用时先清理掉定时器,
  2. 然后用延时定时器调用carousel函数,此函数是一个设置过渡效果的函数,他有一个参数分别是-1(左)和1(右),当为-1时transform:translateX(-700px)就会向左平移,当为1时transform:translateX(700px)就会向右平移,这样我们就可以判断当前是在向哪个方向轮播,后面设置左右按钮就只需要调用并传参就行了,然后将direction设置为当前的方向后面会用。
   //定义一个函数控制函数轮播时间
    function play() {
        clearTimeout(time);
        time = setTimeout(() => carousel(-1), delay);
    }
    //启用轮播定时器
    play();
    
       //平移函数
    function carousel(num) {
        clearTimeout(time);
        //设置过渡
        content.style.transition = "all .35s ease";
        //设置content平移
        content.style.transform = `translateX(${700 * num}px)`;
        //判断轮播方向
        direction = num == -1 ? 'left' : 'right'
    }

    //定义小点点样式函数
    function subscriptStyle(indexContent) {
        //清除所有小点点样式
        for (let i = 0; i < subscript.children.length; i++) {
            subscript.children[i].classList.remove('active')
        }
        //因为是从第二个开始轮播,所以要减一,不然小点点是从第二个开始的
        let num = +indexContent - 1
        //当下标为-1时,让下标为数组长度的最后一个,即最后一张图片
        //由于上面同步了错位-1,导致小点点不会显示最后一个,就是说0-1时是没有东西的但最后一个点又没显示所以当他等于-1时就给最后一个小点点添加上样式
        //例如:
        //content(图片):    0 1 2 3 4
        //subscript(小点点):0 1 2 3 4
        //显示的是1,为了同步content-1然后就成了
        //-1 0 1 2 3 
        // 0 1 2 3 4
        //然后获取第当前显示图片的下标就是0,并设置同样下标为0的小点点可以看到显示的图片下标和小点点的下标是错开的所以4就对应-1
        if (num == -1) num = content.children.length - 1
        //给当前小点点添加样式
        subscript.children[num].classList.add('active')
    }

移动相关的函数

上面的调用后只能移动一个就没了,下面的函数就是关键了

  • 第一个是移动图片函数,就是判断direction是不是"left"字段是就将第一个恶图片放到最后不是就将最后的图片放到第一位
  • 第二个是监听过渡结束事件,当过渡结束后先禁掉过渡,不然调用moveCarousel函数进行图片换位时会有一个回往回过渡的过程,然后将平移清除就。
  • 判断当前鼠标是否在轮播图区域内在的话过渡结束就重新调用play函数就会形成无限循环的情况,就是切换手动和自动。
  • 然后就是调用清除小点点样式函数了,清除掉全部点点的样式,给与当前图片相同标记的小点点加上样式。
   //移动图片函数
    function moveCarousel() {
        const child = direction === "left" ? content.children[0] : content.lastElementChild;
        content.removeChild(child);
        direction === "left" ? content.appendChild(child) : content.prepend(child);
    }
    
    //监听过渡结束
    content.addEventListener("transitionend", () => {
        //禁掉过渡动画
        content.style.transition = "none";
        moveCarousel()
        //重置translateX值,取消过渡效果
        content.style.transform = "none";
        //当开关为true时不执行play
        if (!flag) play()
        //让小点点的样式跟着变
      subscriptStyle(content.children[1].getAttribute('index'))
    })
   

监听左右按钮点击事件

点击后调用carousel平移函数,并传入相应的值来判断左/右,-1/1.

  //监听点击事件
    left.addEventListener("click", () => {
        carousel(-1)
    });
    right.addEventListener("click", () => {
        carousel(1)
    });

监听小点点点击事件

判断是否是点击的小点点是就获取下标、获取当前显示图片的下标计算差值,然后禁掉过渡动画,因为这时候就直接跳图片就行了不需要过渡动画了,
然后再循环调用moveCarousel函数content.children的长度减去差值在加1次就是想要跳转的图片了,加1是因为之前与小点点同步时-1了让第二张当成第一张来显示,反过来控制就会少跳一次所以得加1。这里可以多些一点判断正负来调用moveCarousel函数是向左还是向右跳这样可以少执行几次代码,由于效果已经出来了就懒得弄了。
subscriptStyle传参加1是因为函数内部减1了会导致点击时少一位所以得加1

    //给小点点绑定点击事件
    subscript.addEventListener("click", (e) => {
        if (e.target.className === "list") {
            //获取点击的小点点下标
            const index = e.target.getAttribute('index')
            //获取content子元素下标,当前显示的图片下标
            const indexContent = content.children[1].getAttribute('index')
            //计算点击的小点点和当前显示的图片的下标差值
            const num = indexContent - index
            //禁掉过渡动画
            content.style.transition = "none";
            //根据差值判断循环跳转几次
            for (let i = 0; i < (content.children.length - num) + 1; i++) moveCarousel("left")
            //让小点点的样式跟着变
            subscriptStyle(+index + 1)
        }
    })

监听移入移出事件

引入轮播图时暂停定时器,将开关打开,这样就不会在点击完后监听过渡结束后调用play函数让其变为自动轮播,移出就关闭并调用play函数。

  //移入app盒子停止轮播
    app.addEventListener("mouseenter", () => {
        clearTimeout(time);
        flag = true
        // 移出app盒子继续轮播
        app.addEventListener("mouseleave", () => {
            flag = false
            play()
        })
    })

结束,代码到这里就完成了。
如果不想复制可以在我的GitHub仓库里下载。
这是源码地址:GitHub

代码利用延迟定时器进行平移过渡的实现,然后监听过渡结束后将图片换位,然后再次调用延时定时器,来实现无限循环,不需要记录当前图片是第几个。

这里是提供一下我在网上没找到的写轮播图的思路,希望能对您有所帮助。
代码有什么问题,或写的不够好欢迎在评论区提出。