Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 如何在React中处理父级中的mouseMove事件?_Reactjs_Svg_Draggable_React Hooks_Mousemove - Fatal编程技术网

Reactjs 如何在React中处理父级中的mouseMove事件?

Reactjs 如何在React中处理父级中的mouseMove事件?,reactjs,svg,draggable,react-hooks,mousemove,Reactjs,Svg,Draggable,React Hooks,Mousemove,我尝试在React中实现拖放,并使用SVG元素。问题是如果用户移动鼠标太快,mouseMove不会被触发。它基本上经常会失去牵引力。要解决这个问题,我想我需要在父对象中处理mouseMove,但不确定如何使用React来处理。我尝试了几种不同的方法,但都没有用 我使用ref在父对象上尝试了addEventListener('mousemove',…),但问题是clientX与当前组件的坐标系不同。此外,事件处理程序无权从组件访问任何状态(带有箭头函数的事件)。它维护对任何状态的过时引用 我尝试在

我尝试在React中实现拖放,并使用SVG元素。问题是如果用户移动鼠标太快,
mouseMove
不会被触发。它基本上经常会失去牵引力。要解决这个问题,我想我需要在父对象中处理
mouseMove
,但不确定如何使用React来处理。我尝试了几种不同的方法,但都没有用

我使用ref在父对象上尝试了
addEventListener('mousemove',…)
,但问题是
clientX
与当前组件的坐标系不同。此外,事件处理程序无权从组件访问任何状态(带有箭头函数的事件)。它维护对任何状态的过时引用

我尝试在父对象上的
上下文中设置
clientX
clientY
,然后从
DragMe
组件中将其拉入,但由于某种奇怪的原因,它第一次总是
未定义
,即使我给它一个默认值

以下是我正在使用的代码:

    const DragMe = ({ x = 50, y = 50, r = 10 }) => {
      const [dragging, setDragging] = useState(false)
      const [coord, setCoord] = useState({ x, y })
      const [offset, setOffset] = useState({ x: 0, y: 0 })
      const [origin, setOrigin] = useState({ x: 0, y: 0 })

      const xPos = coord.x + offset.x
      const yPos = coord.y + offset.y

      const transform = `translate(${xPos}, ${yPos})`

      const fill = dragging ? 'red' : 'green'
      const stroke = 'black'

      const handleMouseDown = e => {
        setDragging(true)
        setOrigin({ x: e.clientX, y: e.clientY })
      }

      const handleMouseMove = e => {
        if (!dragging) { return }
        setOffset({
          x: e.clientX - origin.x,
          y: e.clientY - origin.y,
        })
      }

      const handleMouseUp = e => {
        setDragging(false)
        setCoord({ x: xPos, y: yPos })
        setOrigin({ x: 0, y: 0 })
        setOffset({ x: 0, y: 0 })
      }

      return (
        <svg style={{ userSelect: 'none' }}
          onMouseDown={handleMouseDown}
          onMouseUp={handleMouseUp}
          onMouseMove={handleMouseMove}
          onMouseLeave={handleMouseUp}
        >
          <circle transform={transform} cx="0" cy="0" r={r} fill={fill} stroke={stroke} />
        </svg>
      )
    }
const DragMe=({x=50,y=50,r=10})=>{
常量[Draging,SetDraging]=useState(false)
const[coord,setCoord]=useState({x,y})
const[offset,setOffset]=useState({x:0,y:0})
const[origin,setOrigin]=useState({x:0,y:0})
常数xPos=coord.x+offset.x
常数yPos=coord.y+offset.y
const transform=`translate(${xPos},${yPos})`
常量填充=拖动?'red':'green'
常量笔划=‘黑色’
常量handleMouseDown=e=>{
设置拖动(真)
setOrigin({x:e.clientX,y:e.clientY})
}
常量handleMouseMove=e=>{
如果(!拖动){return}
设置偏移量({
x:e.clientX-origin.x,
y:e.clientY-origin.y,
})
}
const handleMouseUp=e=>{
设置拖动(错误)
setCoord({x:xPos,y:yPos})
setOrigin({x:0,y:0})
setOffset({x:0,y:0})
}
返回(
)
}

经过多次实验后,我能够
将EventListener
添加到父画布。我发现我需要
useRef
以允许
mousemove
处理程序查看当前状态。我以前遇到的问题是,
handleParentMouseMove
处理程序对状态的引用已过时,并且从未看到
startDragPos

这就是我想出的解决办法。如果有人知道一个方法来清理这将不胜感激

    const DragMe = ({ x = 50, y = 50, r = 10, stroke = 'black' }) => {
      // `mousemove` will not generate events if the user moves the mouse too fast
      // because the `mousemove` only gets sent when the mouse is still over the object.
      // To work around this issue, we `addEventListener` to the parent canvas.
      const canvasRef = useContext(CanvasContext)

      const [dragging, setDragging] = useState(false)

      // Original position independent of any dragging.  Updated when done dragging.
      const [originalCoord, setOriginalCoord] = useState({ x, y })

      // The distance the mouse has moved since `mousedown`.
      const [delta, setDelta] = useState({ x: 0, y: 0 })

      // Store startDragPos in a `ref` so handlers always have the latest value.
      const startDragPos = useRef({ x: 0, y: 0 })

      // The current object position is the original starting position + the distance
      // the mouse has moved since the start of the drag.
      const xPos = originalCoord.x + delta.x
      const yPos = originalCoord.y + delta.y
      const transform = `translate(${xPos}, ${yPos})`

      // `useCallback` is needed because `removeEventListener`` requires the handler
      // to be the same as `addEventListener`.  Without `useCallback` React will
      // create a new handler each render.
      const handleParentMouseMove = useCallback(e => {
        setDelta({
          x: e.clientX - startDragPos.current.x,
          y: e.clientY - startDragPos.current.y,
        })
      }, [])

      const handleMouseDown = e => {
        setDragging(true)
        startDragPos.current = { x: e.clientX, y: e.clientY }
        canvasRef.current.addEventListener('mousemove', handleParentMouseMove)
      }

      const handleMouseUp = e => {
        setDragging(false)
        setOriginalCoord({ x: xPos, y: yPos })
        startDragPos.current = { x: 0, y: 0 }
        setDelta({ x: 0, y: 0 })
        canvasRef.current.removeEventListener('mousemove', handleParentMouseMove)
      }

      const fill = dragging ? 'red' : 'green'

      return (
        <svg style={{ userSelect: 'none' }}
          onMouseDown={handleMouseDown}
          onMouseUp={handleMouseUp}
        >
          <circle transform={transform} cx="0" cy="0" r={r} fill={fill} stroke={stroke} />
        </svg>
      )
    }
const DragMe=({x=50,y=50,r=10,stroke='black'})=>{
//如果用户移动鼠标太快,`mousemove`将不会生成事件
//因为“mousemove”只有在鼠标仍在对象上时才会被发送。
//为了解决这个问题,我们在父画布中添加了“EventListener”。
const canvasRef=useContext(CanvasContext)
常量[Draging,SetDraging]=useState(false)
//原始位置独立于任何拖动。拖动完成后更新。
const[originalcord,setoriginalcord]=useState({x,y})
//自“mousedown”以来鼠标移动的距离。
const[delta,setDelta]=useState({x:0,y:0})
//将startDragPos存储在'ref'中,以便处理程序始终具有最新的值。
const startDragPos=useRef({x:0,y:0})
//当前对象位置是原始起始位置+距离
//自开始拖动后,鼠标已移动。
常量xPos=原始命令x+增量x
常量yPos=原始命令y+增量y
const transform=`translate(${xPos},${yPos})`
//需要使用“useCallback”,因为“removeEventListener”需要处理程序
//与“addEventListener”相同。如果没有“useCallback”,则
//在每次渲染时创建一个新的处理程序。
const handleParentMouseMove=useCallback(e=>{
塞德尔塔({
x:e.clientX-startDragPos.current.x,
y:e.clientY-startDragPos.current.y,
})
}, [])
常量handleMouseDown=e=>{
设置拖动(真)
startDragPos.current={x:e.clientX,y:e.clientY}
canvasRef.current.addEventListener('mousemove',handleParentMouseMove)
}
const handleMouseUp=e=>{
设置拖动(错误)
setoriginalcord({x:xPos,y:yPos})
startDragPos.current={x:0,y:0}
setDelta({x:0,y:0})
canvasRef.current.removeEventListener('mousemove',handleParentMouseMove)
}
常量填充=拖动?'red':'green'
返回(
)
}

仅隔离在此处工作的代码: 首先,在
render()
函数中找出您的顶级父级是什么,在这里您可能会遇到如下情况:

render() {
  return (
    <div ref={(parent_div) => { this.parent_div = parent_div }}}> 
      // other div stuff 
    </div>
  )
}


尝试添加e.preventDefault();在每个事件方法中,也尝试添加
e.stopPropagation()
我最初尝试过,但问题不是其他事件。问题是
mousemove
仅在鼠标仍在对象上方时发出。当鼠标移动过快时,光标将在更新其位置之前位于对象外部。
this.parent_div.addEventListener('mousemove', function (event) {
  console.log(event.clientX)
}