جاوااسکریپت - کامپوننت سفارشی و قابل کشیدن در ReactJS هنگام استفاده از 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() هر بار که موس را حرکت میدهید فعال میشود، بنابراین اگر به آرامی بیش از ۲۰۰ پیکسل حرکت کنید، این ۲۰۰ تکرار خواهد بود. به جای آن، سعی کنید از onDragStart و onDragEnd استفاده کنید. دموی کامل و عملی.
در نهایت، تغییر شما اینجا در 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}، مرورگر آن را به عنوان یک مورد قابل کشیدن طبیعی در نظر خواهد گرفت (یعنی نسخهای نیمهشفاف از آیتمی که کشیده میشود به صورت بصری در موقعیت نشانگر ظاهر میشود، در حالی که کاربر عنصر را کشیده و حرکت میدهد).
در نهایت، برای اینکه کارها کمی سریعتر شوند، من eventListener ای که برای dragEnd در dragStart() داشتید را حذف کردم.
