集成react locomotive scroll与framer-motion滚动触发动画时出现闪烁及双滚动条问题
解决方案:react-locomotive-scroll 双滚动条+底部闪烁问题
一、先解决双滚动条冲突
- 全局禁用原生滚动条,在全局样式文件中添加:
html, body { overflow: hidden; margin: 0; padding: 0; } - 初始化react-locomotive-scroll时,确保滚动容器高度占满视口,避免原生滚动区域残留:
import { LocomotiveScrollProvider } from 'react-locomotive-scroll'; function App() { return ( <LocomotiveScrollProvider options={{ smooth: true, scrollbar: true, }} watch={[]} > <div data-scroll-container style={{ height: '100vh', overflow: 'hidden' }}> {/* 页面内容 */} </div> </LocomotiveScrollProvider> ); }
二、修复底部闪烁问题
- 同步framer-motion与locomotive-scroll的滚动上下文:
locomotive-scroll是模拟滚动,framer-motion默认监听原生滚动事件,需将滚动目标指向locomotive的容器:import { useScroll, useTransform } from 'framer-motion'; import { useLocomotiveScroll } from 'react-locomotive-scroll'; function AnimatedSection() { const { scroll } = useLocomotiveScroll(); const { scrollYProgress } = useScroll({ target: scroll?.el, // 绑定locomotive滚动容器 offset: ["start start", "end end"] }); const opacity = useTransform(scrollYProgress, [0, 1], [0, 1]); return <section style={{ opacity }}>...</section>; } - 调整平滑滚动参数:
降低缓动系数减少滚动帧不同步,缓解闪烁:<LocomotiveScrollProvider options={{ smooth: true, lerp: 0.05, // 默认0.1,调小降低滚动延迟 scrollbar: true, }} > {/* ... */} </LocomotiveScrollProvider> - 修正容器高度计算:
动态内容(如图片)加载后会改变页面高度,需刷新locomotive的滚动计算:const { scroll } = useLocomotiveScroll(); useEffect(() => { const handleImageLoad = () => scroll?.update(); const images = document.querySelectorAll('img'); images.forEach(img => img.addEventListener('load', handleImageLoad)); return () => images.forEach(img => img.removeEventListener('load', handleImageLoad)); }, [scroll]);
三、替代思路
- 直接使用原生locomotive-scroll:
放弃封装库,手动初始化销毁,规避封装带来的兼容问题:import LocomotiveScroll from 'locomotive-scroll'; import { useEffect, useRef } from 'react'; function App() { const containerRef = useRef(null); const scrollRef = useRef(null); useEffect(() => { if (containerRef.current) { scrollRef.current = new LocomotiveScroll({ el: containerRef.current, smooth: true, scrollbar: true, }); } return () => scrollRef.current?.destroy(); }, []); return ( <div ref={containerRef} data-scroll-container style={{ height: '100vh', overflow: 'hidden' }}> {/* 页面内容 */} </div> ); } - 自定义滚动触发动画逻辑:
监听locomotive的滚动事件,手动控制framer-motion动画:import { useAnimation } from 'framer-motion'; function AnimatedSection() { const controls = useAnimation(); const { scroll } = useLocomotiveScroll(); useEffect(() => { const handleScroll = ({ scrollY }) => { controls.start({ opacity: scrollY > 500 ? 1 : 0 }); }; scroll?.on('scroll', handleScroll); return () => scroll?.off('scroll', handleScroll); }, [scroll, controls]); return <section animate={controls} initial={{ opacity: 0 }}>...</section>; }
内容的提问来源于stack exchange,提问作者user17443811
相关产品推荐
相关产品推荐

