原理
原生实现:监听鼠标的onMouseDown、onMouseMove、onMouseUp事件,对需要进行拖动的元素进行重新定位。
监听鼠标的滚轮事件onWheel,deltaY > 0向下滚动,deltaY < 0向上滚动。
源码
import React, { useRef } from 'react';
import { useReactive, useThrottleFn } from 'ahooks';
const Draggable = ({ children }) => {
const state = useReactive({
start: false,
diffX: 0,
diffY: 0,
});
const ref = useRef<any>(null);
const onMouseDown = (e) => {
state.start = true;
const event = e || window.event;
const diffX = event.clientX - ref.current.offsetLeft;
const diffY = event.clientY - ref.current.offsetTop;
state.diffX = diffX;
state.diffY = diffY;
};
const onMouseMove = (e) => {
if (!state.start) return;
const { diffX, diffY } = state;
const event = e || window.event;
// 距离左侧
let moveX = event.clientX - diffX;
if (moveX < 0) moveX = 0;
else if (moveX > window.innerWidth - ref.current.offsetWidth) {
moveX = window.innerWidth - ref.current.offsetWidth;
}
// 距离顶部
let moveY = event.clientY - diffY;
if (moveY < 0) moveY = 0;
else if (moveY > window.innerHeight - ref.current.offsetHeight) {
moveY = window.innerHeight - ref.current.offsetHeight;
}
ref.current.style.left = moveX + 'px';
ref.current.style.top = moveY + 'px';
};
const onMouseUp = (e) => {
state.start = false;
};
const onWheel = (e) => {
console.log(e);
const { deltaY } = e;
const old = ref.current.style.transform;
ref.current.style.transform = old.replace(/\((.*)+\)/g, (_, p1) => {
const num = Number(p1);
if (deltaY > 0) {
// 向下滚动
return `(${num + 0.1 > 2 ? 2 : num + 0.1})`;
}
// 向上滚动
return `(${num <= 0.3 ? 0.3 : num - 0.1})`;
});
};
const { run } = useThrottleFn(onMouseMove, { wait: 50 });
return (
<div
ref={ref}
className="drag-node"
onMouseDown={onMouseDown}
onMouseMove={run}
onMouseUp={onMouseUp}
onWheel={onWheel}
style={{
transform: 'scale(1)',
}}
>
{children}
</div>
);
};
export default Draggable;
示例
<Draggable>
<div style={{ width: 100, height: 100, background: 'red' }}></div>
</Draggable>