React Flow:拖拽框选节点时实现容器自动滚动
React Flow框选时光标移出容器实现自动滚动
React Flow默认的框选功能在光标移出容器后会停止,要实现拖拽框选时的自动滚动(和拖拽节点时的边缘滚动逻辑一致),可以通过手动监听框选状态和鼠标位置,控制容器滚动来实现。
实现思路
- 跟踪框选的开始/结束状态,判断当前是否处于框选过程中
- 监听全局鼠标移动事件(因为光标可能移出React Flow容器)
- 计算光标相对于容器边缘的距离,当进入设定的阈值范围时,触发容器持续滚动
- 框选结束或光标离开边缘范围时,停止滚动
完整代码示例
import React, { useState, useEffect, useRef } from 'react'; import ReactFlow, { useReactFlow, SelectionMode } from 'reactflow'; import 'reactflow/dist/style.css'; const CustomFlow = () => { const { reactFlowInstance } = useReactFlow(); const [isSelecting, setIsSelecting] = useState(false); const containerRef = useRef(null); const scrollTimerRef = useRef(null); // 缓存React Flow容器元素 useEffect(() => { if (reactFlowInstance) { containerRef.current = reactFlowInstance.container; } }, [reactFlowInstance]); // 框选开始时标记状态 const handleSelectionStart = () => { setIsSelecting(true); }; // 框选结束时重置状态并清理定时器 const handleSelectionEnd = () => { setIsSelecting(false); if (scrollTimerRef.current) { clearInterval(scrollTimerRef.current); scrollTimerRef.current = null; } }; // 监听鼠标移动,处理自动滚动逻辑 useEffect(() => { const handleMouseMove = (e) => { if (!isSelecting || !containerRef.current) return; const container = containerRef.current; const rect = container.getBoundingClientRect(); const scrollSpeed = 5; // 滚动速度,可自行调整 const edgeThreshold = 20; // 触发滚动的边缘距离阈值 let deltaX = 0; let deltaY = 0; // 水平方向滚动判断 if (e.clientX <= rect.left + edgeThreshold) { deltaX = -scrollSpeed; } else if (e.clientX >= rect.right - edgeThreshold) { deltaX = scrollSpeed; } // 垂直方向滚动判断 if (e.clientY <= rect.top + edgeThreshold) { deltaY = -scrollSpeed; } else if (e.clientY >= rect.bottom - edgeThreshold) { deltaY = scrollSpeed; } // 启动或停止滚动定时器 if (deltaX !== 0 || deltaY !== 0) { if (!scrollTimerRef.current) { scrollTimerRef.current = setInterval(() => { container.scrollLeft += deltaX; container.scrollTop += deltaY; }, 16); // 以约60fps的频率滚动 } } else { if (scrollTimerRef.current) { clearInterval(scrollTimerRef.current); scrollTimerRef.current = null; } } }; // 仅在框选状态下添加全局鼠标监听 if (isSelecting) { document.addEventListener('mousemove', handleMouseMove); } // 组件卸载或状态变化时清理事件和定时器 return () => { document.removeEventListener('mousemove', handleMouseMove); if (scrollTimerRef.current) { clearInterval(scrollTimerRef.current); } }; }, [isSelecting]); return ( <ReactFlow selectionMode={SelectionMode.Box} onSelectionStart={handleSelectionStart} onSelectionEnd={handleSelectionEnd} // 这里可以添加你的节点、边等配置 /> ); }; export default CustomFlow;
关键细节说明
- 全局
mousemove监听:因为光标移出容器后,容器内的鼠标事件不会触发,所以需要监听全局事件来捕获光标位置 - 定时器控制滚动:用
setInterval实现持续滚动,模拟拖拽节点时的平滑滚动效果 - 阈值和速度调整:
edgeThreshold控制光标距离边缘多远触发滚动,scrollSpeed控制滚动的快慢,可根据需求自行修改 - 资源清理:在组件卸载或框选结束时,务必清除定时器和事件监听,避免内存泄漏
内容的提问来源于stack exchange,提问作者Andrei
相关产品推荐
相关产品推荐

