1:Draggable.js
import React, {useState, useCallback, useMemo, useEffect} from 'react';
const POSITION = {x: 0, y: 0};
const Draggable = ({children, id, onDrag, onDragEnd}) => {
const [state, setState] = useState({
isDragging: false,
origin: POSITION,
translation: POSITION
});
const handleMouseDown = useCallback(({clientX, clientY}) => {
setState(state => ({
...state,
isDragging: true,
origin: {x: clientX - state.translation.x, y: clientY - state.translation.y}
}));
}, []);
const handleMouseMove = useCallback(({ clientX, clientY }) => {
const width = document.getElementById(id).offsetWidth;
const height = document.getElementById(id).offsetHeight;
const translation = { x: clientX - state.origin.x, y: clientY - state.origin.y };
// 边界控制
if (translation.x < 0) {
translation.x = 0;
}
if (translation.y < 0) {
translation.y = 0;
}
if (translation.x + width > window.innerWidth) {
translation.x = window.innerWidth - width;
}
if (translation.y + height > window.innerHeight) {
translation.y = window.innerHeight - height;
}
setState(state => ({
...state,
translation
}));
onDrag({translation, id});
}, [state.origin, onDrag, id]);
const handleMouseUp = useCallback(() => {
setState(state => ({
...state,
isDragging: false
}));
onDragEnd();
}, [onDragEnd]);
useEffect(() => {
if (state.isDragging) {
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseup', handleMouseUp);
} else {
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('mouseup', handleMouseUp);
}
}, [state.isDragging, handleMouseMove, handleMouseUp]);
const styles = useMemo(() => ({
cursor: state.isDragging ? '-webkit-grabbing' : '-webkit-grab',
transform: `translate(${state.translation.x}px, ${state.translation.y}px)`,
transition: state.isDragging ? 'none' : 'transform 500ms',
zIndex: state.isDragging ? 2 : 1,
position: state.isDragging ? 'absolute' : 'relative'
}), [state.isDragging, state.translation]);
return (
<div style={styles} onMouseDown={handleMouseDown}>
{children}
</div>
);
};
export default Draggable;
2、App.js
import React from 'react'
import Draggable from './components/dragger/Draggable'
import style from './App.module.css'
const App = () => {
const onDrag = () => {
console.log('onDrag')
}
const onDragEnd = () => {
console.log('onDragEnd')
}
return (
<div className={style.app}>
<Draggable id="drag" onDrag={onDrag} onDragEnd={onDragEnd}>
<div className={style.drag} id="drag">拖拽组件</div>
</Draggable>
</div>
)
}
export default App