封装
思路:
- 如果拖拽时box相对于自己的位移为 0, 那么鼠标移动多少box就移动多少
- 如果拖拽时box相对于自己的位移为 3, 那么translateX = 3 + 鼠标位移
const useDrager = () => () => useDrag()
export function useDrag() {
const target = useRef<HTMLDivElement>(null);
const [style, setStyle] = useState<CSSProperties>({})
useEffect(() => {
let dragging = false;
// 鼠标相对于视口的初始位置
let start = { x:0, y: 0};
// transform:
// box相对于自己的位置
// 如果拖拽时box相对于自己的位移为 0, 那么鼠标移动多少box就移动多少
// 如果拖拽时box相对于自己的位移为 3, translateX = 3 + 鼠标位移
let transform = { x:0, y: 0}
target.current?.addEventListener("mousedown", function (e: MouseEvent) {
dragging = true;
start = getMouse(e) // 记录鼠标初始位置
transform = getTransform(target.current) // 获取dom相对于自己的位置
});
document.addEventListener("mousemove", function (e) {
if (dragging===false) return;
const sx = e.clientX - start.x // 鼠标位移x
const sy = e.clientY - start.y // 鼠标位移y
const x = transform.x + sx
const y = transform.y + sy
setStyle({ transform: `translate(${x}px, ${y}px)`});
});
document.addEventListener("mouseup", function (e) {
dragging = false;
});
}, [target]);
return {
ref: target,
style
}
}
// 获取鼠标在视口中的位置
function getMouse(e: MouseEvent) {
return {
x: e.clientX,
y: e.clientY
}
}
// 获取dom元素的translateX, translateY, 文心一言搜的方法
function getTransform(dom) {
const style = window.getComputedStyle(dom);
const transformMatrix = style.transform
const matrix = transformMatrix.match(/^matrix\((.+)\)$/);
if (matrix) {
const values = matrix[1].split(',').map(parseFloat);
// const translateX = values[12] || 0;
return {
y: values.pop(),
x: values.pop(),
}
}
return {x: 0, y: 0}
}
使用
const Test = function () {
const props = useDrag()
const bind = useDrager()
return <>
<div {...props} className='box' />
<div {...bind()} className='box' />
<div {...bind()} className='box' />
<div {...bind()} className='box' />
<div {...bind()} className='box' />
<div {...bind()} className='box' />
</>
};