震惊?!无缝轮播图中不让用setInterval控制图片切换?

767 阅读4分钟

看到题目,我想大家中的很多人应该都是和我一样的疑惑,不用定时器去实现,那该咋整?毕竟用setInterval控制无缝轮播图中的图片切换太常见了,在网上随便搜一搜基本上都是如下这种写法。

    timerID = setInterval(function () {
            // 获得它当前位置 要求子元素和父级元素都要定位
            var current = dom.offsetLeft;
            // 移动距离减去当前距离,每次前进10px,直到到达,到达后停止定时器
            if (Math.abs(target - current) > 10) {
                current += target > current ? 10 : -10;
                // 赋值给left
                dom.style.left = current + "px";
            } else {
                dom.style.left = target + "px";
            }
            if (current == target) {
                clearInterval(timerID);
            }
        }, 10);

至于其他类型的写法,当然有,但是很少见,比如 elementUi 中是控制各个子元素的 transform ,但是很遗憾,老版的有bug,我也没想出好的解决方案,至于新的 plus 版本的还没看过,不做评论。
为了后续讲解方便,先放完整代码

起因

因为项目中有个页面涉及到的 setInterval 这个API比较多,导致了一些意料之外的问题,我们老大就很生气,表示不要再让这个API出现在项目中,凡是涉及到的统统替换掉。然后我负责的是轮播图,我听了就很尴尬,毕竟这一部分的代码都是我抄的,我只调了样式,没办法,只能接着搜了呗(写代码是不可能的,这辈子都不可能的,只能靠着CV大佬的代码勉强度日的样子)。

经过

在搜了两个小时之后毫无所获,然后脑海里突然闪过一个念头:
既然不能用js那么麻烦,即使改也只是用两个setTimeout替换一个setInterval ,为啥不能用css呢,即使页面卡死了,也不影响css动画啊,毕竟这两个家伙都不在一个线程里面。

结果

于是我在脑海里面构思了一下,
首先克隆第一个盒子,把它放在最后
然后transform父盒子,当走到最后一个的时候转到显示第二个盒子那里
如下图所示:

其中的原理和其他大佬写的是一致的,我就不多废话了,我就说说不一样的部分
既然是css动画,那我就先把css放出来

.is-animating{
    transition: all 0.8s;
}

具体操作部分如下所示

  • 第一步:初始化内容,html如下
    <div id="container">
        <div class="button">
            <div class="pre"></div>
            <div class="next"></div>
        </div>
        <ul class="list is-animating" style="height: 400px;">
            <li>0<img src="../img1.image"></li>
            <li>1<img src="../img2.image"></li>
            <li>2<img src="../img3.image"></li>
            <li>3<img src="../img4.image"></li>
        </ul>
    </div>

主要js如下

const width = 500// 图片的宽度
const lists = document.querySelector(".list")
  • 第二步:具体操作,每向前走一步,元素的 transform 属性值 translateX 都要减去一张图片的宽度,直到最后一张
const left = -current * width
lists.style.transform = `translateX(${left}px)`;
  • 第三步:增加判断,当走到最后一个的时候,将动画效果去除,并将 translateX 的值改为0,之后再添加动画,再将 translateX 改为指定位置,逻辑图如下

重点来了,此时要加一个延时器,让translateX(0px)走完,否则会出现下面这种状况导致无缝轮播失败
为了避免这种状况,需要加一个延时,等待上一步的translate走完,核心代码如下:

lists.classList.remove("is-animating")
lists.style.transform = `translateX(${-max * width}px)`;

setTimeout(() => {
    lists.classList.add("is-animating")
    translate(current)
    handleDot(current)
}, 0)

加上之后就正常了,如下图

以上就是本次分享的全部内容了,如果有更好的方法去实现的,欢迎拍砖!