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

嵌套使用react-router Link与react-draggable-core导致拖拽异常

嘿,这个嵌套组件的冲突问题我太熟啦!你遇到的核心问题是拖拽操作被浏览器误判为点击,触发了Link的跳转逻辑,导致拖拽功能异常。下面给你几种靠谱的解决方案,按需选就行:

原因分析

当你拖拽DraggableCore包裹的Link时,拖拽的mousedown/mousemove事件结束后,浏览器会把mouseup动作识别为点击,进而触发Link的跳转,打断了拖拽的正常流程。我们需要做的就是区分「拖拽」和「点击」两种操作,不让它们互相干扰。


方案1:用useRef标记拖拽状态,阻止拖拽后的点击跳转

这个方案简单直接,通过标记拖拽状态,在点击Link时判断是否是拖拽后的误触,从而阻止跳转:

import { useRef } from 'react';
import { DraggableCore } from 'react-draggable';
import { Link } from 'react-router-dom';

function DraggableIconLink({ newAddress }) {
  // 用useRef保存拖拽状态,避免组件重渲染时丢失
  const isDraggingRef = useRef(false);

  const handleDragStart = () => {
    isDraggingRef.current = true;
  };

  const handleDragStop = () => {
    // 延迟重置,避免拖拽结束瞬间的点击被误判
    setTimeout(() => {
      isDraggingRef.current = false;
    }, 100);
  };

  const handleLinkClick = (e) => {
    // 如果是拖拽状态,阻止Link的默认跳转行为
    if (isDraggingRef.current) {
      e.preventDefault();
      e.stopPropagation();
    }
  };

  return (
    <DraggableCore 
      onStart={handleDragStart} 
      onStop={handleDragStop}
    >
      <Link to={newAddress} onClick={handleLinkClick}>
        <GlyphShow />
      </Link>
    </DraggableCore>
  );
}

方案2:通过拖拽距离判断操作类型(更精准)

如果担心方案1的延迟判断不够准确,可以通过计算鼠标移动的距离来区分「点击」和「拖拽」——当移动距离超过设定阈值(比如5px),就判定为拖拽,阻止跳转:

import { useRef, useState } from 'react';
import { DraggableCore } from 'react-draggable';
import { Link } from 'react-router-dom';

function DraggableIconLink({ newAddress }) {
  const isDraggingRef = useRef(false);
  const [startMousePos, setStartMousePos] = useState({ x: 0, y: 0 });

  const handleDragStart = (e) => {
    setStartMousePos({ x: e.clientX, y: e.clientY });
    isDraggingRef.current = false;
  };

  const handleDrag = (e) => {
    // 计算鼠标移动的欧氏距离
    const distance = Math.sqrt(
      Math.pow(e.clientX - startMousePos.x, 2) + 
      Math.pow(e.clientY - startMousePos.y, 2)
    );
    // 超过5px就标记为拖拽
    if (distance > 5) {
      isDraggingRef.current = true;
    }
  };

  const handleLinkClick = (e) => {
    if (isDraggingRef.current) {
      e.preventDefault();
      e.stopPropagation();
    }
  };

  return (
    <DraggableCore 
      onStart={handleDragStart} 
      onDrag={handleDrag}
    >
      <Link to={newAddress} onClick={handleLinkClick}>
        <GlyphShow />
      </Link>
    </DraggableCore>
  );
}

方案3:手动控制跳转(最灵活)

放弃使用Link组件,改用普通元素包裹图标,点击时手动调用路由跳转函数,同时处理拖拽事件,完全规避组件冲突:

import { useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import { DraggableCore } from 'react-draggable';

function DraggableIconLink({ newAddress }) {
  const navigate = useNavigate();
  const isDraggingRef = useRef(false);

  const handleDragStart = () => {
    isDraggingRef.current = true;
  };

  const handleDragStop = () => {
    setTimeout(() => {
      isDraggingRef.current = false;
    }, 100);
  };

  const handleIconClick = () => {
    if (!isDraggingRef.current) {
      navigate(newAddress);
    }
  };

  return (
    <DraggableCore 
      onStart={handleDragStart} 
      onStop={handleDragStop}
    >
      <div 
        onClick={handleIconClick}
        style={{ cursor: 'pointer' }} // 保持点击的视觉提示
      >
        <GlyphShow />
      </div>
    </DraggableCore>
  );
}

这三种方案都能解决你的问题,推荐方案2或3,它们的兼容性和准确性更好~

内容的提问来源于stack exchange,提问作者moeinghasemi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:16:14