使用 onMouseMove() 时,ReactJS 中的自定义、可拖动组件太慢

Custom, Draggable component too slow in ReactJS when Using onMouseMove()

我正在尝试创建一个可拖动的 preact 组件。如果光标快速移动,我当前的实现就会中断。这是代码。

export { Draggable };

import { h } from "preact";
import { useState } from "preact/hooks";

const Draggable = (props: any) => {
    const [styles, setStyles] = useState({});
    const [diffPos, setDiffPos] = useState({ diffX: 0, diffY: 0 });
    const [isDragging, setIsDragging] = useState(false);

    const dragStart = (e: MouseEvent): void => {
        const boundingRect =
            (e.currentTarget as HTMLElement).getBoundingClientRect();

        setDiffPos({
            diffX: e.screenX - boundingRect.left,
            diffY: e.screenY - boundingRect.top,
        });

        setIsDragging(true);
    }

    const dragging = (e: MouseEvent): void => {
        if (isDragging === true) {
            const left = e.screenX - diffPos.diffX;
            const top = e.screenY - diffPos.diffY;

            setStyles({ left: left, top: top });
        }
    }

    const dragEnd = (): void => {
        setIsDragging(false);
    }

    return (
        <div
            class="draggable"
            style={{ ...styles, position: "absolute" }}
            onMouseDown={dragStart}
            onMouseMove={dragging}
            onMouseUp={dragEnd}
        >
            {props.children}
        </div>
    );
}

我试图通过创建一个 mouseup 事件侦听器来修复它,但是如果我将鼠标移动到快速,元素就会停止拖动。

这是我尝试的修复方法:

export { Draggable };

import { h } from "preact";
import { useState } from "preact/hooks";

const Draggable = (props: any) => {
    const [styles, setStyles] = useState({});
    const [diffPos, setDiffPos] = useState({ diffX: 0, diffY: 0 });
    const [isDragging, setIsDragging] = useState(false);

    const dragStart = (e: MouseEvent): void => {
        const boundingRect =
            (e.currentTarget as HTMLElement).getBoundingClientRect();

        setDiffPos({
            diffX: e.screenX - boundingRect.left,
            diffY: e.screenY - boundingRect.top,
        });

        setIsDragging(true);

        // ------------------------------------------------------------ Added an event listener
        document.addEventListener("mouseup", dragEnd, { once: true });
    }

    const dragging = (e: MouseEvent): void => {
        if (isDragging === true) {
            const left = e.screenX - diffPos.diffX;
            const top = e.screenY - diffPos.diffY;

            setStyles({ left: left, top: top });
        }
    }

    const dragEnd = (): void => {
        setIsDragging(false);
    }

    return (
        <div
            class="draggable"
            style={{ ...styles, position: "absolute" }}
            onMouseDown={dragStart}
            onMouseMove={dragging}
            // -------------------------------------------------------- Removed onMouseUp
        >
            {props.children}
        </div>
    );
}

问题是每次移动鼠标时 onMouseMove() 都会触发,因此,如果您非常缓慢地移动超过 200 个像素,那就是 200 次迭代。尝试使用 onDragStartonDragEndFull working demo.

最终,您的更改将在 render()...

 return (
   <div
     class="draggable"
     style={{ ...styles, position: "absolute" }}
     onDragStart={(e) => dragStart(e)}
     onDragEnd={(e) => dragging(e)}
     draggable={true}
   >
     {props.children}
   </div>
 );

我使用 dragEnd(),所以实际上只有两个事件会随着拖动而触发:开始和结束。每次移动时都会触发 MouseMove,在拖动过程中可能会触发数百次。

此外,通过给它额外的 draggable={true} 参数,浏览器会将其视为 naturally-draggable 项目(即,拖动项目的 semi-opaque 版本将在视觉上显示在光标的位置,当用户拖动元素时)。

最后,为了稍微加快速度,我删除了 eventListener 你在 dragStart() 中为 dragEnd 设置的 eventListener