You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Flow:拖拽框选节点时实现容器自动滚动

React Flow框选时光标移出容器实现自动滚动

React Flow默认的框选功能在光标移出容器后会停止,要实现拖拽框选时的自动滚动(和拖拽节点时的边缘滚动逻辑一致),可以通过手动监听框选状态和鼠标位置,控制容器滚动来实现。

实现思路

  1. 跟踪框选的开始/结束状态,判断当前是否处于框选过程中
  2. 监听全局鼠标移动事件(因为光标可能移出React Flow容器)
  3. 计算光标相对于容器边缘的距离,当进入设定的阈值范围时,触发容器持续滚动
  4. 框选结束或光标离开边缘范围时,停止滚动

完整代码示例

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 14:15:09