为什么我在 React 中的可拖动组件在鼠标移动前移动到光标之前?

如何解决为什么我在 React 中的可拖动组件在鼠标移动前移动到光标之前?

这是我的第一个 Stack Overflow 问题,所以请耐心等待,如果您需要更多信息,请告诉我!我基本上是在重新创建一个简化的 Beyond20 可交互地图供 Dungeon Master 使用。为首次初级开发应用构建项目组合。

无论如何,我已经用纯背景颜色的 div 制作了可移动的“碎片”,带有简短的文本名称,可以在板上的地图图像周围移动。与其导入像 React DnD 这样的预构建库,我想从头开始执行此操作以更好地了解机制。我将我的移动逻辑存储在组件 Draggable(如下)中。然而,每当我拖动一个“片段”时,该片段会逐渐移动到光标的前面(注意:它不会像我在其他地方读到的那样落后,它会向光标移动的任何方向缓慢向前滑动),并且这种行为会发生在我测试过的每个显示器屏幕上,除了我写代码的原始显示器。还要注意的是,可拖动组件在任何拖动事件上都会从光标处移动一段可复制的距离,这意味着,如果我拖动元素,例如 300 像素,它最终将始终位于光标前面的相同距离处。

我希望这是有道理的。如果我能澄清任何事情,请告诉我。任何和所有的建议都非常感谢!

可拖动组件:

import React,{ useState,useEffect,useRef } from 'react';


function Draggable({ 
  children,position,updatePosition,deleteIcon,id
 }) {
  const [drop,setDrop] = useState({ x: position.x,y: position.y })
  const dragRef = useRef()

  const handlePointerDown = (e) => {
    window.addEventListener('pointermove',handleDragMove);
    window.addEventListener('pointerup',handlePointerUp);
  };
  
  const handleDragMove = (e) => {
      dragRef.current.style.left = `${dragRef.current.offsetLeft + e.movementX}px`
      dragRef.current.style.top = `${dragRef.current.offsetTop + e.movementY}px`
  };

  const handlePointerUp = (e) => {

    const aspectBox = document.getElementById('aspectRatioBox')
    const bounding = dragRef.current.getBoundingClientRect();

    if(bounding.x < 100 && bounding.y < 100) {
      //Below conditional is for deleting an Icon if dropped within a specific area on page

      try {
        deleteIcon(id)
      } catch(exception) {
        console.log('Unable to delete icon',exception)
      }
    } else if (drop.x !== dragRef.current.style.left && drop.y !== dragRef.current.style.top) {  
      //This is for updating the position in the server through socket.io and saving to database

      setDrop({
        x: `${dragRef.current.style.left.replace(/px/g,'')/aspectBox.clientWidth*100}%`,y: `${dragRef.current.style.top.replace(/px/g,'')/aspectBox.clientHeight*100}%`
      })
    }
    window.removeEventListener('pointermove',handleDragMove);
    window.removeEventListener('pointerup',handlePointerUp);
  }



  const preventBehavior =(e) => {
    e.preventDefault();
  }

  useEffect(() => {
    window.addEventListener('touchmove',preventBehavior,{passive: false})

    return () => {
      window.removeEventListener('pointerup',handlePointerUp)
      window.removeEventListener('touchmove',{passive: false})
      window.removeEventListener('pointermove',handleDragMove);
      window.removeEventListener('pointerup',handlePointerUp);
    } 

  },[])


  const firstRender = useRef(true);
  useEffect(() => {
    if(!firstRender.current) {
      updatePosition({ 
        x: drop.x,y: drop.y 
      },id)
    }
  },[drop.x,drop.y] ) 

  useEffect(() => { firstRender.current = false },[])
  return (
    <div
      onPointerDown={handlePointerDown}
      style={{top: position.y,left: position.x}}
      className="draggableBox"
      ref={dragRef}
    >
      {children}
    </div>

  )
}

export default Draggable

解决方法

因此,经过许多小时的 Google Foo 失败后,我找到了解决问题的可靠方法。

我不相信这解决了我的根本问题是可拖动元素领先于光标,但我相信这与我通过 e.movementX 和 e.movementY 更新位置的附加性质有关。

const handlePointerDown = (e) => {

  const { left,top }  = dragRef.current.getBoundingClientRect()
  posRef.current = {
    x: left - e.clientX,y: top - e.clientY
  }

  
   window.addEventListener('pointermove',handleDragMove);
   window.addEventListener('pointerup',handlePointerUp);

   e.stopPropagation();
   e.preventDefault();
};
  

const handleDragMove = (e) => {
  const aspectBox = document.getElementById('aspectRatioBox').getBoundingClientRect()

  dragRef.current.style.left = `${(e.clientX + posRef.current.x - aspectBox.left)/aspectBox.width*100}%`
  dragRef.current.style.top = `${(e.clientY + posRef.current.y - aspectBox.top)/aspectBox.height*100}%`
 
  e.stopPropagation();
  e.preventDefault();


};

我通过可拖动元素在其中移动的框的增量和光标的 e.Client 位置获得可拖动元素的相对位置。我添加了一个 ref posRef,它允许更精确地移动图标,而不是立即将光标捕捉到图标的左上角。

希望这能帮助任何发现自己处于类似情况的人!!!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res