参考文档一:https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/108
参考文档二:https://blog.csdn.net/vhwfr2u02q/article/details/79492303

如果需要用css实现无缝轮播,请点传送门

requestAnimationFrame方法的作用为在屏幕刷新每一帧时执行一次回调函数,用requestAnimationFrame实现即表示轮播效果是js实现,接下来上效果图:

用requestAnimationFrame实现无缝轮播图-LMLPHP

下面给出示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<style>
    .view-box{width: 200px; height: 200px; overflow: hidden;}
    .container{width: 1000px; position: relative; padding: 0; font-size: 0;}
    .item{width: 200px; height: 200px; display: inline-block;}
    .item1{background-color: red;}
    .item2{background-color: blue;}
    .item3{background-color: yellow;}
    .item4{background-color: green;}
</style>
<body>

<div class="view-box">
    <ul class="container">
        <li class="item item1"></li>
        <li class="item item2"></li>
        <li class="item item3"></li>
        <li class="item item4"></li>
        <li class="item item1"></li>
    </ul>
</div>

<input type="button" onclick="start()" value="启动">
<input type="button" onclick="stop()" value="停止">

</body>
<script>
    let slicing = () => {
        //requestAnimationFrame方法的作用为在屏幕刷新每一帧时执行一次回调函数
        const requestAnimationFrame =
            window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame
        const cancelAnimationFrame =
            window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame
        //scrollNode为需要执行轮播动作的容器
        const scrollNode = document.getElementsByClassName("container")[0]
        //单个轮播元素宽度
        const itemWidth = 200
        //distance为轮播时容器的最大偏移距离(通常为容器的宽度减去第一个轮播元素的宽度)
        const distance = scrollNode.clientWidth - itemWidth
        //由于容器的定位为相对定位,则可以通过修改style的left来达到移动效果
        scrollNode.style.left = scrollNode.style.left || 0
        //容器的偏移距离保存在window对象的__offset属性中
        window.__offset = window.__offset || 0

        /**
         * requestId:为requestAnimationFrame执行的返回值,用于停止动画(和setInterval的返回值功能类似)
         * sliceStatus:轮播状态(start为启动,stop为停止)
         * wait:轮播暂停已等待帧数
         * waitMax:轮播暂停最大等待帧数
         */

        let requestId = null, sliceStatus = "start", wait = 0, waitMax = 60
        //每一帧执行的回调函数
        const scrollLeft = () => {
            if (window.__offset % itemWidth === 0 && wait < waitMax) {
                wait++;
            }
            else {
                if (window.__offset % itemWidth === 0 && wait === waitMax) {
                    wait = 0;
                }
                //轮播速度
                const speed = 2
                //刷新容器偏移距离
                window.__offset = window.__offset + speed
                //设置容器偏移距离
                scrollNode.style.left = -window.__offset + 'px'
            }
            /**
             * 当容器偏移距离达到最大偏移距离时,重置容器偏移距离,继续从头开始移动
             * 由于最后一个轮播元素是第一个轮播元素的复制,所以看起来就是无缝轮播的效果
             */
            if (distance <= window.__offset) window.__offset = 0
            //通过递归的方式循环调用
            requestId = requestAnimationFrame(scrollLeft)
        }
        requestId = requestAnimationFrame(scrollLeft)
        return (status) => {
            if (sliceStatus === status) return
            status === "start" ? requestId =
                requestAnimationFrame(scrollLeft) : cancelAnimationFrame(requestId)
            sliceStatus = status
        }
    }
    let slice = null
    let start = () => slice === null ? slice = slicing() : slice("start")
    let stop = () => slice("stop")
</script>
</html>
08-27 18:06