我主要是一个后端工程师,一直在尝试实现并失败,因为我在React中制作了一个简单的拖放操作。
首先,我将向您展示不使用反跳的行为: no-debounce
这是带有反跳的行为: with-debounce
我从here获得的去抖功能做了一些修改。
我认为我有两个问题,一个是快速闪烁,应该解决抖动问题,另一个是错误的left
,我不知道该如何解决。由于某些原因,onDrag,rect.left也添加了父母的所有左边界(100 + 10)。这是在Chrome和Safari上发生的。
我的问题是,如何使此拖放工作?我究竟做错了什么?我的代码如下:
import React, {
Dispatch,
MouseEvent,
RefObject,
SetStateAction,
useEffect,
useRef,
useState
} from "react";
const useDebounce = (callback: any, delay: number) => {
const latestCallback = useRef(callback);
const latestTimeout = useRef(1);
useEffect(() => {
latestCallback.current = callback;
}, [callback]);
return (obj: any) => {
const { event, args } = obj;
event.persist();
if (latestTimeout.current) {
clearTimeout(latestTimeout.current);
}
latestTimeout.current = window.setTimeout(
() => latestCallback.current(event, ...args),
delay
);
};
};
const setPosition = (
event: any,
setter: any
) => {
const rect = event.target.getBoundingClientRect();
const clientX: number = event.pageX;
console.log('clientX: ', clientX)
// console.log(rect.left)
setter(clientX - rect.left)
};
const Slider: React.FC = () => {
const [x, setX] = useState(null);
const handleOnDrag = useDebounce(setPosition, 100)
return (
<div style={{ position: "absolute", margin: '10px' }}>
<div
style={{ position: "absolute", left: "0", top: "0" }}
onDragOver={e => e.preventDefault()}
>
<svg width="300" height="10">
<rect
y="5"
width="300"
height="2"
rx="10"
ry="10"
style={{ fill: "rgb(96,125,139)" }}
/>
</svg>
</div>
<div
draggable={true}
onDrag={event => handleOnDrag({event, args: [setX]})}
// onDrag={event => setPosition(event, setX)}
style={{
position: "absolute",
left: (x || 0).toString() + "px",
top: "5px",
width: "10px",
height: "10px",
padding: "0px",
}}
>
<svg width="10" height="10" style={{display:"block"}}>
<circle cx="5" cy="5" r="4" />
</svg>
</div>
</div>
);
};
谢谢。
答案 0 :(得分:1)
可拖动和onDrag有其自身的麻烦。通过简单的鼠标事件尝试了我的手。
您可以在以下沙箱中找到有效的代码
其来源如下
import React, { useRef, useState, useEffect, useCallback } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const isDragging = useRef(false);
const dragHeadRef = useRef();
const [position, setPosition] = useState(0);
const onMouseDown = useCallback(e => {
if (dragHeadRef.current && dragHeadRef.current.contains(e.target)) {
isDragging.current = true;
}
}, []);
const onMouseUp = useCallback(() => {
if (isDragging.current) {
isDragging.current = false;
}
}, []);
const onMouseMove = useCallback(e => {
if (isDragging.current) {
setPosition(position => position + e.movementX);
}
}, []);
useEffect(() => {
document.addEventListener("mouseup", onMouseUp);
document.addEventListener("mousedown", onMouseDown);
document.addEventListener("mousemove", onMouseMove);
return () => {
document.removeEventListener("mouseup", onMouseUp);
document.removeEventListener("mousedown", onMouseDown);
document.removeEventListener("mousemove", onMouseMove);
};
}, [onMouseMove, onMouseDown, onMouseUp]);
return (
<div
style={{
flex: "1",
display: "flex",
alignItems: "center",
justifyContent: "center",
height: "100vh"
}}
>
<div
style={{
height: "5px",
width: "500px",
background: "black",
position: "absolute"
}}
>
<div
ref={dragHeadRef}
style={{
left: `${position}px`,
transition: 'left 0.1s ease-out',
top: "-12.5px",
position: "relative",
height: "30px",
width: "30px",
background: "black",
borderRadius: "50%"
}}
/>
</div>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
逻辑的症结是e.movementX
,它返回自上次发生该事件以来鼠标沿x轴移动的距离量。使用它来设置dragHeader的左侧位置