You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现原生JS控制的div滑块无限循环滚动效果?

div滑块无缝无限滚动实现方案

问题原因

当前实现通过直接修改滚动容器scrollLeft值控制位移,原生滚动容器内容存在明确起止边界,滚动到首尾位置时会自然停止,无法实现循环效果。
要做到无缝无限滚动,核心是通过「首尾克隆占位+边界无感知复位」的方式,消除滚动边界带来的停顿感。

核心实现逻辑

  • 初始化阶段:在滑块内容头部克隆尾部若干幻灯片、尾部克隆头部若干幻灯片,制造足够的滚动过渡余量,克隆的项总宽度只要能覆盖滑块容器可视宽度即可
  • 初始位置校准:页面加载后把滚动位置偏移到真实首项的位置,把前置的克隆项隐藏在可视区域外
  • 边界复位:每次滚动结束后判断当前位置,如果滚到最前端的克隆区域,就瞬间无动画跳转到真实尾部对应的位置;如果滚到最后端的克隆区域,就瞬间无动画跳转到真实头部对应的位置,整个跳转过程用户完全感知不到,不会出现视觉断层
  • 增加防抖逻辑,避免快速点击按钮导致滚动错乱

完整可运行代码

JavaScript 部分

原有简单的加减scrollLeft逻辑替换为以下代码:

document.addEventListener('DOMContentLoaded', function() {
    const slider = document.getElementById('slider')
    const buttonLeft = document.getElementById('slide_left')
    const buttonRight = document.getElementById('slide_right')
    const thumbnails = slider.querySelectorAll('.thumbnail')
    const itemWidth = 90 // 单个幻灯片宽度80px + 10px右间距
    const cloneCount = 4 // 克隆项数量,覆盖350px可视宽度足够
    let isAnimating = false

    // 首尾插入克隆项
    for(let i = thumbnails.length - cloneCount; i < thumbnails.length; i++) {
        slider.prepend(thumbnails[i].cloneNode(true))
    }
    for(let i = 0; i < cloneCount; i++) {
        slider.append(thumbnails[i].cloneNode(true))
    }

    // 初始位置对准真实首项
    slider.scrollLeft = itemWidth * cloneCount

    // 边界复位逻辑
    function checkBoundary() {
        isAnimating = false
        // 滚到左克隆区,瞬间跳转到真实尾部位置
        if(slider.scrollLeft <= 0) {
            slider.style.scrollBehavior = 'auto'
            slider.scrollLeft = thumbnails.length * itemWidth
        }
        // 滚到右克隆区,瞬间跳转到真实头部位置
        if(slider.scrollLeft >= (thumbnails.length + cloneCount) * itemWidth) {
            slider.style.scrollBehavior = 'auto'
            slider.scrollLeft = cloneCount * itemWidth
        }
    }

    slider.addEventListener('scroll', function() {
        if(isAnimating) return
        window.requestAnimationFrame(checkBoundary)
    })

    // 左右按钮点击事件
    buttonLeft.addEventListener('click', function() {
        if(isAnimating) return
        isAnimating = true
        slider.style.scrollBehavior = 'smooth'
        slider.scrollLeft -= itemWidth
    })

    buttonRight.addEventListener('click', function() {
        if(isAnimating) return
        isAnimating = true
        slider.style.scrollBehavior = 'smooth'
        slider.scrollLeft += itemWidth
    })
})

CSS 部分

原有样式基本保留,不要给#slider加scroll-behavior: smooth属性,滚动行为完全由JS控制,避免复位时出现动画穿帮:

body{
    background-color: #555;
    height: 100vh;
    display: grid;
    align-items: center;
    justify-items: center;
    font-family: 'Helvetica';
}

div#slide_wrapper{
    width: 440px;
    display: flex;
    justify-content: space-between;
    height: fit-content;
}

div#slider{
    width: 350px;
    display: flex;
    height: fit-content;
    flex-wrap: nowrap;
    overflow: hidden;
}

div.thumbnail{
    min-width: 80px;
    min-height: 80px;
    cursor: pointer;
    display: grid;
    place-items: center;
    font-size: 30px;
}

div.thumbnail:not(:last-child){
    margin-right: 10px;
}

div.thumbnail:nth-child(1){background-color: darkturquoise;}
div.thumbnail:nth-child(2){background-color: goldenrod;}
div.thumbnail:nth-child(3){background-color: rebeccapurple;}
div.thumbnail:nth-child(4){background-color: powderblue;}
div.thumbnail:nth-child(5){background-color: firebrick;}
div.thumbnail:nth-child(6){background-color: sienna;}
div.thumbnail:nth-child(7){background-color: bisque;}
div.thumbnail:nth-child(8){background-color: navy;}

div#slide_wrapper > button{
    height: fit-content;
    align-self: center;
    font-size: 24px;
    font-weight: 800;
    border: none;
    outline: none;
}

div#slide_wrapper > button:hover{
    cursor: pointer;
    background-color: dodgerblue;
    color: #fff;
}

HTML 部分

原有结构完全不需要修改:

<div id="slide_wrapper">
    <button id="slide_left" class="slide_arrow">&#10094;</button>
    <div id="slider">
        <div class="thumbnail active">1</div>
        <div class="thumbnail">2</div>
        <div class="thumbnail">3</div>
        <div class="thumbnail">4</div>
        <div class="thumbnail">5</div>
        <div class="thumbnail">6</div>
        <div class="thumbnail">7</div>
        <div class="thumbnail">8</div>
    </div>
    <button id="slide_right" class="slide_arrow">&#10095;</button>
</div>

适配说明

如果后续调整幻灯片尺寸、数量或者滑块容器宽度,只需要对应修改itemWidth(单个幻灯片占位宽度)和cloneCount(保证克隆项总宽度≥滑块容器可视宽度即可),其他逻辑无需调整。

内容的提问来源于stack exchange,提问作者Matt Don

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 20:36:33