如何在使用Floating UI时禁用滚动中的transform动画?
问题描述
我使用floating-ui库实现了一个悬浮菜单组件,通过transform属性的动画来平滑调整菜单位置,但滚动时该动画会生效,带来了体验问题。请问在React中能否仅在滚动时为悬浮元素添加类来禁用该动画?
解决方案
完全可以实现,核心思路是监听页面滚动状态,给悬浮元素添加状态标识,再通过CSS在滚动时覆盖动画规则,禁用transform过渡。
1. 完善滚动状态监听逻辑
优化滚动监听逻辑,滚动触发时立即标记为滚动中,滚动停止后延迟一段时间再标记为非滚动(避免滚动过程中状态频繁切换),同时监听编辑器容器的滚动(因为你的编辑器是带滚动条的.Editor):
export const BubbleMenu = ({ editor, children }: Props) => { const [open, setOpen] = useState(false); const [scrolling, setScrolling] = useState(false); const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null); useEffect(() => { const handleScroll = () => { setScrolling(true); // 清除之前的延迟定时器 if (scrollTimeoutRef.current) { clearTimeout(scrollTimeoutRef.current); } // 滚动停止后300ms标记为非滚动 scrollTimeoutRef.current = setTimeout(() => { setScrolling(false); }, 300); }; // 监听window和编辑器容器的滚动 const editorContainer = editor.view.dom.closest('.Editor'); window.addEventListener("scroll", handleScroll); editorContainer?.addEventListener("scroll", handleScroll); return () => { window.removeEventListener("scroll", handleScroll); editorContainer?.removeEventListener("scroll", handleScroll); if (scrollTimeoutRef.current) { clearTimeout(scrollTimeoutRef.current); } }; }, [editor]); // ... 其余代码保持不变 };
2. 调整CSS规则,滚动时禁用动画
修改SCSS代码,当data-scrolling="true"时,直接移除transform的过渡效果:
/* 原有动画规则保持不变 */ #floating { transition-property: opacity, transform; } #floating[data-status="open"], #floating[data-status="close"] { transition-property: opacity, transform; transition-duration: 250ms; } #floating[data-status="initial"], #floating[data-status="close"] { opacity: 0; } #floating[data-status="initial"][data-placement^="top"], #floating[data-status="close"][data-placement^="top"] { transform: translateY(-5px); } #floating[data-status="initial"][data-placement^="bottom"], #floating[data-status="close"][data-placement^="bottom"] { transform: translateY(5px); } #floating[data-status="initial"][data-placement^="left"], #floating[data-status="close"][data-placement^="left"] { transform: translateX(5px); } #floating[data-status="initial"][data-placement^="right"], #floating[data-status="close"][data-placement^="right"] { transform: translateX(-5px); } /* 滚动时禁用transform动画 */ #floating-wrapper[data-scrolling="true"] { transition: none !important; } #floating-wrapper[data-scrolling="true"] #floating { transition-property: opacity !important; /* 保留透明度动画,仅禁用transform */ } .Editor { max-height: 300px; overflow: auto; }
3. 确保状态正确传递到DOM
你的代码已经在#floating-wrapper上添加了data-scrolling={scrolling},这部分无需修改,确保该属性能正确反映当前滚动状态即可。
原理说明
- 滚动触发时,
scrolling变为true,DOM上的data-scrolling="true"生效,CSS强制移除transform的过渡动画,菜单跟随滚动直接定位,无动画卡顿。 - 滚动停止300ms后,
scrolling恢复为false,动画规则重新生效,菜单的正常位置调整(比如切换选中内容时)会有平滑过渡。
内容的提问来源于stack exchange,提问作者Ugus
相关产品推荐
相关产品推荐

