我正在尝试创建一个允许我调整元素大小的钩子。我使用这个答案作为参考点并创建了以下内容。
调整大小可以,但不准确。调整大小手柄不跟随光标,并且会偶尔移动。
任何人都可以帮我理解这个钩子有什么问题吗?
挂钩:
interface Dimensions {
width: number | null;
height: number | null;
}
interface UseResizableProps {
elementRef: React.RefObject<HTMLDivElement>;
handleRef: React.RefObject<HTMLDivElement>;
}
function useResizable({ elementRef, handleRef }: UseResizableProps) {
const dimensions = useRef<Dimensions>({ width: null, height: null });
// Since we dont know the size that the element should initialize to,
// we need to grab the sizes from the element rect
useEffect(() => {
if (elementRef.current) {
const rect = elementRef.current.getBoundingClientRect();
dimensions.current = { height: rect.height, width: rect.width };
}
}, [elementRef]);
useEffect(() => {
function handleMouseDownE(mouseDownEvent: MouseEvent) {
const startPosition = {
x: mouseDownEvent.pageX,
y: mouseDownEvent.pageY,
};
function onMouseMove(mouseMoveEvent: MouseEvent) {
if (
dimensions.current.height === null ||
dimensions.current.width === null
) {
return;
}
dimensions.current = {
width:
dimensions.current.width - startPosition.x + mouseMoveEvent.pageX,
height: dimensions.current.height,
};
if (
elementRef?.current?.style.width !== undefined &&
dimensions.current.width
) {
const px = `${dimensions.current.width}px`;
elementRef.current.style.width = px;
}
}
function onMouseUp() {
document.body.removeEventListener("mousemove", onMouseMove);
}
document.body?.addEventListener("mousemove", onMouseMove);
document.body?.addEventListener("mouseup", onMouseUp, { once: true });
}
handleRef?.current?.addEventListener("mousedown", handleMouseDownE);
});
}
挂钩用法:
function App() {
const elementRef = useRef<HTMLDivElement>(null);
const handleRef = useRef<HTMLDivElement>(null);
useResizable({ elementRef, handleRef });
return (
<div className="App">
<div className="resizable" ref={elementRef}>
<div className="resize-handle" ref={handleRef}></div>
</div>
</div>
);
}
款式:
.resizable {
width: 500px;
height: 500px;
background-color: lightpink;
position: relative;
}
.resize-handle {
width: 5px;
height: 100%;
background-color: orangered;
right: 0;
position: absolute;
cursor: e-resize;
}
问题在于宽度计算。您将 currentDimensions 称为 mouseDown 事件首次触发时的尺寸,然后在 mouseMouse 触发时修改它。 解决方案是在 mouseDown 事件触发时获取尺寸的副本,例如 来自:
function handleMouseDownE(mouseDownEvent: MouseEvent) {
const startPosition = {
x: mouseDownEvent.pageX,
y: mouseDownEvent.pageY,
};
function onMouseMove(mouseMoveEvent: MouseEvent) {
if (
dimensions.current.height === null ||
dimensions.current.width === null
) {
return;
}
dimensions.current = {
width:
dimensions.current.width - startPosition.x + mouseMoveEvent.pageX,
height: dimensions.current.height,
};
if (
elementRef?.current?.style.width !== undefined &&
dimensions.current.width
) {
const px = `${dimensions.current.width}px`;
elementRef.current.style.width = px;
}
}
致:
function handleMouseDownE(mouseDownEvent: MouseEvent) {
const startDimensions = { ...dimensions.current }; // <<<< Add this
const startPosition = {
x: mouseDownEvent.pageX,
y: mouseDownEvent.pageY,
};
function onMouseMove(mouseMoveEvent: MouseEvent) {
if (
dimensions.current.height === null ||
dimensions.current.width === null
) {
return;
}
dimensions.current = {
width:
startDimensions.width - startPosition.x + mouseMoveEvent.pageX, // <<<< Add this
height: startDimensions.height,
};
if (
elementRef?.current?.style.width !== undefined &&
dimensions.current.width
) {
const px = `${dimensions.current.width}px`;
elementRef.current.style.width = px;
}
}