JavaScript双向Marquee动画循环复位时闪烁故障求助
双向Marquee跑马灯动画闪烁回跳问题
我正在用JavaScript类实现双向跑马灯效果,通过CSS的transform属性结合translate3d()方法,根据类实例配置控制容器左右平移。核心动画逻辑如下:
const moveReel = () => { if (this.direction === "left") { currentPosition -= this.speed; if (currentPosition < -totalWidth - 1) { currentPosition = 0; } } else { currentPosition += this.speed; if (currentPosition > 1) { currentPosition = -totalWidth; } } wrapper.style.transform = `translate3d(${currentPosition}px, 0, 0)`; requestAnimationFrame(moveReel); };
当currentPosition被设置为0时,动画出现闪烁故障,内容会回跳1-2像素。我尝试过将currentPosition改为-0.1这类小负数,也调整了速度参数,但都没解决问题,而且速度越快故障越明显。
以下是完整代码:
Reeller JavaScript类
class Reeller { constructor(options) { this.containers = document.querySelectorAll(options.container); this.speed = options.speed || 1; this.direction = options.reversed ? "right" : "left"; // 默认向左 this.containers.forEach((container) => { let wrapper = container.querySelector(options.wrapper); let items = wrapper.querySelectorAll(options.itemSelector); // 计算单个元素宽度(含margin-right) const itemWidth = items[0].offsetWidth + parseFloat(getComputedStyle(items[0]).marginRight); // 计算所有元素总宽度 const totalWidth = itemWidth * items.length; // 克隆元素并添加到wrapper中 const cloneItems = []; let count = 10; while (count--) { for (let j = 0; j < items.length; j++) { const clonedItem = items[j].cloneNode(true); cloneItems.push(clonedItem); // prepend()没用,之前的蠢想法 wrapper.appendChild(clonedItem); } } // 设置wrapper宽度以容纳所有元素 wrapper.style.width = totalWidth + "px"; // 初始化交叉观察器,检测最后一个克隆元素是否进入视口 const observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if ( entry.isIntersecting && entry.target === cloneItems[cloneItems.length - 1] ) { // 移除所有克隆元素 cloneItems.forEach((item) => item.remove()); cloneItems.length = 0; // 将wrapper位置重置为初始状态 wrapper.style.transform = `translate3d(${-totalWidth}px, 0, 0)`; } }); }); // 观察最后一个克隆元素 observer.observe(cloneItems[cloneItems.length - 1]); // 动画逻辑 let currentPosition = -totalWidth; const moveReel = () => { if (this.direction === "left") { currentPosition -= this.speed; if (currentPosition < -totalWidth - 1) { currentPosition = 0; } } else { currentPosition += this.speed; if (currentPosition > 1) { currentPosition = -totalWidth; } } wrapper.style.transform = `translate3d(${currentPosition}px, 0, 0)`; requestAnimationFrame(moveReel); }; requestAnimationFrame(moveReel); }); } }
HTML代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> .my__reel { width: 100%; overflow: hidden; } .my__reel__wrap { display: flex; padding: 20px; } .my__reel__item { flex: 0 0 auto; min-width: 100px; height: auto; margin-right: 40px; } .h1 { font-size: 50px; font-weight: 200; } .my-reel-item-2 { background: rgb(222, 231, 255); padding: 5px 20px; border-radius: 20px; } </style> </head> <body> <!-- 第一个跑马灯 --> <div class="my__reel my-reel-1"> <div class="my__reel__wrap my-reel-wrap-1"> <div class="my__reel__item my-reel-item-1"> <h1>REEEEEL</h1> </div> </div> </div> <!-- 第二个跑马灯,故障更明显 --> <div class="my__reel my-reel-2"> <div class="my__reel__wrap my-reel-wrap-2"> <div class="my__reel__item my-reel-item-2"> <h1>REEEEEL</h1> </div> <div class="my__reel__item my-reel-item-2"> <h1>WOW</h1> </div> <div class="my__reel__item my-reel-item-2"> <h1>AHHHHHHH</h1> </div> </div> </div> <!-- JavaScript --> <script src="reeller.js"></script> <script> new Reeller({ container: ".my-reel-1", wrapper: ".my-reel-wrap-1", itemSelector: ".my-reel-item-1", speed: 0, }); new Reeller({ container: ".my-reel-2", wrapper: ".my-reel-wrap-2", itemSelector: ".my-reel-item-2", speed: 2, reversed: true, }); </script> </body> </html>
内容的提问来源于stack exchange,提问作者Alohe
相关产品推荐
相关产品推荐

