如何解决快速滚动时scrollLeft()值丢失的问题?
无限轮播组件快速滚动时的scrollLeft值间隙问题
我开发可拖拽/滚动的无限轮播组件已经好几个小时了,但遇到一个棘手问题:快速滚动时,carousel.scrollLeft()无法跟上滚动节奏,出现值间隙。为实现无限轮播的“无缝跳转”逻辑,需要carousel.scrollLeft()精准触达设定的触发值,但直接用if (carousel.scrollLeft() <= scrollTriggerStart)会引发诸多异常问题。相关代码如下:
JavaScript 代码
const carousel = $('.carousel'); const carouselCards = carousel.children('.card'); let cardAmount = 3; // 轮播内可见的卡片数量 carouselCards.slice(-cardAmount).get().reverse().forEach((e) => { let card = $(e); carousel.prepend(card.prop('outerHTML')); // 将最后3张卡片反向插入到第一张卡片前 }) carouselCards.slice(0, cardAmount).get().forEach((e) => { let card = $(e); carousel.append(card.prop('outerHTML')); // 将前3张卡片追加到最后一张卡片后 }) let scrollTriggerStart = Math.round(carouselCards.outerWidth() + carouselCards.outerWidth() / 2 - carousel.outerWidth() / 2); // 第二张卡片位于轮播中心时的精确scrollLeft值 let scrollTriggerEnd = Math.round(carousel[0].scrollWidth - carouselCards.outerWidth() - carouselCards.outerWidth() / 2 - carousel.outerWidth() / 2); // 倒数第二张卡片位于轮播中心时的精确scrollLeft值 let seamlessPosStart = carouselCards.length * carouselCards.outerWidth() - carouselCards.outerWidth() / 2 - carousel.outerWidth() / 2; // 与倒数第二张卡片对应的目标scrollLeft值 let seamlessPosEnd = carousel[0].scrollWidth - carouselCards.length * carouselCards.outerWidth() + carouselCards.outerWidth() / 2 - carousel.outerWidth() / 2; // 与第二张卡片对应的目标scrollLeft值 infiniteScroll = () => { if (carousel.scrollLeft() <= scrollTriggerStart) { carousel.addClass('no-transition'); carousel.scrollLeft(seamlessPosEnd); carousel.removeClass('no-transition'); } else if (carousel.scrollLeft() >= scrollTriggerEnd) { carousel.addClass('no-transition'); carousel.scrollLeft(seamlessPosStart); carousel.removeClass('no-transition'); } } carousel.on('scroll', infiniteScroll);
CSS 代码
*, ::before, ::after { box-sizing: border-box; margin: 0; padding: 0; } * { font: inherit; } html, body { min-height: 100vh; } ul:has([class]) { list-style: none; } body { font-family: sans-serif; display: flex; align-items: center; justify-content: center; } .wrapper { position: relative; display: flex; flex-direction: column; align-items: center; gap: 5em; width: 100%; padding-inline: 10em; } .carousel { display: grid; grid-auto-flow: column; grid-auto-columns: calc(100% / 2); overflow-x: auto; scroll-snap-type: x mandatory; border-radius: .5em; scroll-behavior: smooth; scrollbar-width: none; width: 100%; } .carousel::-webkit-scrollbar { display: none; } .carousel .card { aspect-ratio: 1; scroll-snap-align: center; background: rgba(255, 0, 0, 0.25); border-radius: .5rem; display: flex; align-items: center; justify-content: center; font-size: 2rem; scale: 0.95; border: 2px solid transparent; transition: 250ms ease; } .card.selected { border: 2px solid red; scale: 1; } .no-transition { scroll-behavior: auto; } .no-transition .card { scroll-snap-align: unset; } /* .slider-interactive { display: flex; gap: 4em; } .slider-interactive > * { background: rgba(255,0,0,0.25); aspect-ratio: 1; border-radius: 50%; cursor: pointer; transition: 250ms ease; width: 1.5rem; } .slider-interactive > *.selected { background: red; } */
HTML 代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="style.css"> <title>Infinite carousel</title> </head> <body> <div class="wrapper"> <ul class="carousel"> <li class="card"> <h2>Card 1</h2> </li> <li class="card"> <h2>Card 2</h2> </li> <li class="card"> <h2>Card 3</h2> </li> <li class="card"> <h2>Card 4</h2> </li> <li class="card"> <h2>Card 5</h2> </li> </ul> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script src="main.js"></script> </body> </html>
内容的提问来源于stack exchange,提问作者Itsjul1an
相关产品推荐
相关产品推荐

