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

拖拽后React与纯HTML的onMouseMove事件表现差异问题

React拖拽元素后父元素onMouseMove事件不触发的问题解决

将红色div(子元素)拖拽到蓝色div(父元素)后,鼠标悬停在红色div上时,React中蓝色div的onMouseMove事件不会触发,但相同逻辑在纯HTML中可以正常触发。

纯HTML示例代码

<div>
    <div
      id="child"
      draggable="true"
      ondragstart="drag(event)"
      style="background-color: red; width: 200px; height: 200px;"
    >
        1. Put me on blue container<br/>
        2. Check console<br/>
        3. Move mouse over containers
    </div>

    <div
      id="newParent"
      ondrop="drop(event)"
      onmousemove="mouseMove(event)"
      ondragover="allowDrop(event)"
      style="background-color: blue; width: 400px; height: 400px;"
    ></div>
</div>

<script>
  function drag(ev) {
    ev.dataTransfer.setData('id', ev.target.id);
  }

  function drop(ev) {
    ev.preventDefault();
    var data = ev.dataTransfer.getData('id');
    var element = document.getElementById(data);
    ev.target.appendChild(element);
  }

  function allowDrop(ev) {
    ev.preventDefault();
  }

  function mouseMove(event) {
    console.clear();
    console.log('onMouseMoveDiagram', event.clientX, event.clientY);
  }
</script>

React示例代码

export function App(props) {
    return (
        <div>
            <div
                id="child"
                draggable
                onDragStart={(ev) => {
                    ev.dataTransfer.setData('id', ev.currentTarget.id);
                }}
                style={{ backgroundColor: 'red', width: '200px', height: '200px' }}
            >
                1. Put me on blue container
                <br />
                2. Check console
                <br />
                3. Move mouse over containers
            </div>

            <div
                id="newParent"
                onDrop={(ev) => {
                    ev.preventDefault();
                    const data = ev.dataTransfer.getData('id');
                    const element = document.getElementById(data);
                    ev.currentTarget.appendChild(element);
                }}
                onMouseMove={(event) => {
                    console.clear();
                    console.log('onMouseMoveDiagram', event.clientX, event.clientY);
                }}
                onDragOver={(ev) => ev.preventDefault()}
                style={{ backgroundColor: 'blue', width: '400px', height: '400px' }}
            ></div>
        </div>
    );
}

问题原因

核心冲突在于React的合成事件机制与原生DOM操作的不兼容:

  • React的所有合成事件(比如onMouseMove)并非直接绑定在目标元素上,而是委托到根节点统一处理。
  • 当你通过原生appendChild方法将红色div添加到蓝色div后,这个红色div脱离了React的DOM管理范围。鼠标在它上面移动时,原生事件会被它捕获,但无法通过React的事件委托机制冒泡到父元素的合成事件回调中。
  • 纯HTML中事件直接绑定在元素上,原生事件的冒泡机制不受限制,因此父元素的onmousemove能正常触发。

解决方案

方案1:用React状态管理元素归属(推荐)

遵循React的数据流原则,通过状态控制子元素的父容器,让React负责DOM渲染和事件绑定:

import { useState } from 'react';

export function App(props) {
    const [childContainer, setChildContainer] = useState('default');

    const handleDragStart = (ev) => {
        ev.dataTransfer.setData('id', ev.currentTarget.id);
    };

    const handleDrop = () => {
        setChildContainer('newParent');
    };

    const handleMouseMove = (event) => {
        console.clear();
        console.log('onMouseMoveDiagram', event.clientX, event.clientY);
    };

    return (
        <div>
            {childContainer === 'default' && (
                <div
                    id="child"
                    draggable
                    onDragStart={handleDragStart}
                    style={{ backgroundColor: 'red', width: '200px', height: '200px' }}
                >
                    1. Put me on blue container
                    <br />
                    2. Check console
                    <br />
                    3. Move mouse over containers
                </div>
            )}

            <div
                id="newParent"
                onDrop={handleDrop}
                onMouseMove={handleMouseMove}
                onDragOver={(ev) => ev.preventDefault()}
                style={{ backgroundColor: 'blue', width: '400px', height: '400px' }}
            >
                {childContainer === 'newParent' && (
                    <div
                        id="child"
                        draggable
                        onDragStart={handleDragStart}
                        style={{ backgroundColor: 'red', width: '200px', height: '200px' }}
                    >
                        1. Put me on blue container
                        <br />
                        2. Check console
                        <br />
                        3. Move mouse over containers
                    </div>
                )}
            </div>
        </div>
    );
}

方案2:手动给子元素添加原生事件监听

如果必须直接操作DOM,可以在拖拽完成后,给红色div添加原生mousemove事件监听,手动触发父元素的事件处理函数:

import { useRef } from 'react';

export function App(props) {
    const parentRef = useRef(null);

    const handleMouseMove = (event) => {
        console.clear();
        console.log('onMouseMoveDiagram', event.clientX, event.clientY);
    };

    const handleDrop = (ev) => {
        ev.preventDefault();
        const data = ev.dataTransfer.getData('id');
        const element = document.getElementById(data);
        parentRef.current.appendChild(element);
        // 给子元素绑定原生事件,手动调用父元素的处理函数
        element.addEventListener('mousemove', handleMouseMove);
    };

    return (
        <div>
            <div
                id="child"
                draggable
                onDragStart={(ev) => {
                    ev.dataTransfer.setData('id', ev.currentTarget.id);
                }}
                style={{ backgroundColor: 'red', width: '200px', height: '200px' }}
            >
                1. Put me on blue container
                <br />
                2. Check console
                <br />
                3. Move mouse over containers
            </div>

            <div
                ref={parentRef}
                id="newParent"
                onDrop={handleDrop}
                onMouseMove={handleMouseMove}
                onDragOver={(ev) => ev.preventDefault()}
                style={{ backgroundColor: 'blue', width: '400px', height: '400px' }}
            ></div>
        </div>
    );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 10:23:19