视差场景下滚动触发div垂直轮播滑动动画实现方法
视差容器垂直滚动轮播实现方案
原有代码问题梳理
- 滚动方向判断失效:
lastScrollTop变量定义在scroll事件回调内部,每次滚动触发都会被重置为0,完全无法识别向上/向下滚动行为 - 动画被强制中断:给
.div1添加动画类后立刻执行hide(),元素直接被隐藏,滑动动画没有执行机会 - 缺少反向交互动画:向上回滚时
.div2没有对应离场动画,直接硬切显示.div1,不符合轮播的平滑过渡要求 - 动画参数不合理:9秒的动画时长远超出滚动交互的即时反馈阈值,且子元素未做堆叠定位,切换时会出现布局错位
- 无重复触发防护:scroll事件触发频率极高,没有加动画状态锁,会导致动画类重复添加、状态混乱
修正后完整代码
CSS 部分
body { height: 200vh; margin: 0; } /* 视差容器做定位基准 */ .scrollTest { position: fixed; top: 0; left: 0; width: 100%; height: 100vh; overflow: hidden; } /* 两个内容层绝对定位堆叠在同一位置 */ .div1, .div2 { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; } .div2 { display: none; } /* 向上滑出离场动画 */ .slide-up-out { animation: slideUp 0.5s ease forwards; } @keyframes slideUp { from { transform: translateY(0); opacity: 1; } to { transform: translateY(-100%); opacity: 0; } } /* 向下滑出离场动画 */ .slide-down-out { animation: slideDown 0.5s ease forwards; } @keyframes slideDown { from { transform: translateY(0); opacity: 1; } to { transform: translateY(100%); opacity: 0; } }
JS 部分
// 把状态变量提到事件外部,持久化存储 let lastScrollTop = 0; let isAnimating = false; // 动画锁,执行中不响应新触发 const triggerThreshold = 100; const $scrollTest = $("#scrollTest"); const $div1 = $(".div1"); const $div2 = $(".div2"); window.addEventListener("scroll", function() { // 动画执行中直接返回,避免冲突 if (isAnimating) return; const currentScroll = window.scrollY; const triggerPoint = $scrollTest.offset().top + triggerThreshold; const scrollDirection = currentScroll > lastScrollTop ? 'down' : 'up'; // 向下滚动超过阈值,且当前显示div1时,触发div1上滑离场 if (currentScroll > triggerPoint && $div1.is(':visible') && scrollDirection === 'down') { isAnimating = true; $div1.addClass("slide-up-out"); // 等动画执行完成再切换显示状态 $div1.one('animationend', function() { $div1.hide().removeClass("slide-up-out"); $div2.show(); isAnimating = false; }) } // 向上滚动低于阈值,且当前显示div2时,触发div2下滑离场 if (currentScroll <= triggerPoint && $div2.is(':visible') && scrollDirection === 'up') { isAnimating = true; $div2.addClass("slide-down-out"); // 等动画执行完成再切换显示状态 $div2.one('animationend', function() { $div2.hide().removeClass("slide-down-out"); $div1.show(); isAnimating = false; }) } // 更新上次滚动位置,处理滚动到顶部的边界情况 lastScrollTop = currentScroll <= 0 ? 0 : currentScroll; });
HTML 部分
<head> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> </head> <body> <div class="scrollTest" id="scrollTest"> <div class="div1"> <img src="https://i.pinimg.com/736x/f7/eb/d8/f7ebd86ff10d7d738d975f227a591600.jpg" width="50%" /> </div> <div class="div2"> <img src="https://i.pinimg.com/736x/85/60/5a/85605a84fe1acc6e16ff5a84255b41ab.jpg" width="50%" /> </div> </div> </body>
实现逻辑说明
- 用transform实现滑动动画比
top属性性能更好,不会触发重排,动画流畅度更高 - 动画锁
isAnimating保证同一时间只有一个动画在执行,避免快速滚动时状态错乱 - 通过
animationend事件监听动画完成时机,再切换元素显示状态,保证动画完整播放 - 滚动方向通过对比当前滚动值和上次存储的滚动值判断,逻辑准确
- 两个内容层用绝对定位堆叠,切换时不会出现页面布局跳动
- 容器添加
overflow: hidden,滑出容器的内容会被隐藏,完全匹配垂直轮播的视觉效果
内容的提问来源于stack exchange,提问作者TechDev
相关产品推荐
相关产品推荐

