移动端IntersectionObserver触发滚动动画延迟问题求助
移动端快速滚动时IntersectionObserver触发动画延迟问题
我通过IntersectionObserver实现了元素可见时触发文字动画的功能,但在移动端快速滚动到目标div时,动画无法立即触发,存在明显延迟。
相关代码
JavaScript 动画触发函数
export function scrollAnimation(selector, options = {}) { let component = document.querySelectorAll(selector); component = Array.from(component); component.forEach((comp) => { addObserver(comp, options); // comp.addEventListener("animationend", function () { // comp.classList.remove("active"); // }); }); } function addObserver(comp, options) { let observer = new IntersectionObserver((entries, observer) => { entries.forEach((entry) => { if (entry.isIntersecting) { entry.target.classList.add("active"); // observer.unobserve(entry.target); } else { // setTimeout(() => { entry.target.classList.remove("active"); // }, "250"); } }); }, options); observer.observe(comp); }
React 组件调用代码
useEffect(() => { scrollAnimation(".animate", { rootMargin: "0px", threshold: 0, }); const isVerified = localStorage.getItem("isVerified"); setIsAgeVerifyModal(!isVerified); }, [location]);
CSS 动画样式
.active { animation-name: fadeInUp; animation-duration: 0.75s; animation-fill-mode: both; } @keyframes fadeInUp { 0% { opacity: 0; transform: translate3d(100%, 0, 0); } 100% { opacity: 1; transform: translateZ(0); } }
补充:尝试制作JS Fiddle示例时发现keyframes存在兼容性问题。
解决办法
优化IntersectionObserver配置
- 修改
rootMargin为-50px 0,让元素提前50px进入检测范围,抵消滚动延迟;将threshold设为0.1,当元素10%进入视口时触发动画,比0更灵敏:scrollAnimation(".animate", { rootMargin: "-50px 0px", threshold: 0.1, });
- 修改
调整动画触发逻辑
- 元素离开视口时添加延迟再移除
active类,避免快速滚动时动画频繁启停:function addObserver(comp, options) { let observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { entry.target.classList.add("active"); } else { const timer = setTimeout(() => { if (!entry.isIntersecting) { entry.target.classList.remove("active"); } }, 300); // 清理定时器防止内存泄漏 entry.target._timer && clearTimeout(entry.target._timer); entry.target._timer = timer; } }); }, options); observer.observe(comp); }
- 元素离开视口时添加延迟再移除
提升CSS动画性能
- 简化
transform属性,改用translateX替代translate3d,减少GPU渲染开销:@keyframes fadeInUp { 0% { opacity: 0; transform: translateX(100%); } 100% { opacity: 1; transform: translateX(0); } } - 给目标元素添加
will-change提示浏览器优化:.animate { will-change: transform, opacity; }
- 简化
合并Observer实例
- 原代码每个元素创建一个Observer,改成单个实例监听所有元素,降低性能消耗:
export function scrollAnimation(selector, options = {}) { const components = Array.from(document.querySelectorAll(selector)); const observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { entry.target.classList.add("active"); } else { const timer = setTimeout(() => { if (!entry.isIntersecting) { entry.target.classList.remove("active"); } }, 300); entry.target._timer && clearTimeout(entry.target._timer); entry.target._timer = timer; } }); }, options); components.forEach(comp => observer.observe(comp)); }
- 原代码每个元素创建一个Observer,改成单个实例监听所有元素,降低性能消耗:
内容的提问来源于stack exchange,提问作者user11631308
相关产品推荐
相关产品推荐

