React Three Fiber滚动到顶部异常:设置offset=0后自动回到底部
问题:React Three Fiber中ScrollControls无法实现滚动到顶部,设置scroll.offset=0后页面跳回底部
我用Three.js结合React Three Fiber开发项目,场景里集成了ScrollControls和部分HTML内容,现在遇到滚动到顶部功能失效的问题:点击触发top状态后,设置scroll.offset = 0,页面会短暂回到顶部,但立刻跳回底部。
代码片段如下:
const scroll = useScroll() useEffect(() => { scroll.offset = 0 },[top]) useFrame(() => { tl.current.seek(scroll.offset * tl.current.duration()) tl2.current.seek(scroll.offset * tl2.current.duration()) const content = document.getElementById('App'); const totalHeight = content.clientHeight; let scrollDist = totalHeight*scroll.offset window.scrollTo({ top:scrollDist, behavior:"smooth" }) })
问题根源
你在useFrame中手动调用window.scrollTo的逻辑,和ScrollControls的内部滚动同步机制产生了冲突:当你通过useEffect设置scroll.offset=0后,useFrame会立刻根据当前scroll.offset计算滚动距离并调用window.scrollTo,而ScrollControls会监听浏览器的scroll事件,反过来更新scroll.offset,形成循环触发,最终导致页面跳回底部。
解决方案
- 移除
useFrame中的window.scrollTo逻辑:ScrollControls本身已经负责同步Three.js场景动画和页面滚动状态,手动调用window.scrollTo完全多余,是冲突的核心原因。 - 优化滚动到顶部的逻辑:在
useEffect中同时同步ScrollControls的滚动位置和浏览器滚动,避免循环触发。
修改后的代码:
import { useContext } from 'react' import { useScroll } from '@react-three/drei' import { ScrollControlsContext } from '@react-three/drei/ScrollControls' const scroll = useScroll() const { scroll: scrollControls } = useContext(ScrollControlsContext) useEffect(() => { // 重置scroll.offset scroll.offset = 0 // 让ScrollControls滚动到顶部 scrollControls.scrollTo(0, { smooth: true }) // 同步浏览器滚动到顶部 window.scrollTo({ top: 0, behavior: 'smooth' }) }, [top, scroll, scrollControls]) useFrame(() => { // 仅保留动画时间线的更新逻辑 tl.current.seek(scroll.offset * tl.current.duration()) tl2.current.seek(scroll.offset * tl2.current.duration()) })
注意事项
- 确保你的组件被包裹在
<ScrollControls>组件内部,这样才能正确获取ScrollControlsContext。 - 如果不需要平滑滚动,可以去掉
behavior: 'smooth'参数,减少动画冲突的可能。
内容的提问来源于stack exchange,提问作者Ayush Patel
相关产品推荐
相关产品推荐

