fix: 修复预览面板拖拽分隔线快速移动时宽度不跟手的问题

根因:ResizeHandle 使用 document.addEventListener('mousemove') 监听拖拽,
当鼠标快速移到 iframe(HTML 预览)上方时,iframe 捕获了鼠标事件,
document 上的 mousemove 回调不再触发,导致宽度停止更新。

修复:将 mouse events 替换为 pointer events + setPointerCapture。
- onMouseDown → onPointerDown + setPointerCapture
- 在元素上直接监听 onPointerMove/onPointerUp(不再挂 document 事件)
- pointer capture 确保所有后续事件锁定到拖拽手柄,即使鼠标移到 iframe 上方
- 添加 touch-none CSS 防止触屏浏览器默认行为干扰拖拽
- 代码更简洁:不再需要手动 addEventListener/removeEventListener

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
7418andClaude Opus 4.6 committed 2026-02-27 15:49:01 +08:00
1 parent 056e908b72
commit b1e6b0bfac
1 file changed
+31 -25
+31 -25
View File
@@ -13,42 +13,48 @@ export function ResizeHandle({ side, onResize, onResizeEnd }: ResizeHandleProps)
const isDragging = useRef(false);
const startX = useRef(0);
const handleMouseDown = useCallback(
(e: React.MouseEvent) => {
const handlePointerDown = useCallback(
(e: React.PointerEvent) => {
e.preventDefault();
isDragging.current = true;
startX.current = e.clientX;
// Capture pointer so all subsequent events route here, even over iframes
(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
document.body.style.cursor = "col-resize";
document.body.style.userSelect = "none";
const handleMouseMove = (ev: MouseEvent) => {
if (!isDragging.current) return;
const delta = ev.clientX - startX.current;
startX.current = ev.clientX;
onResize(delta);
};
const handleMouseUp = () => {
isDragging.current = false;
document.body.style.cursor = "";
document.body.style.userSelect = "";
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
onResizeEnd?.();
};
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
},
[onResize, onResizeEnd]
[]
);
const handlePointerMove = useCallback(
(e: React.PointerEvent) => {
if (!isDragging.current) return;
const delta = e.clientX - startX.current;
startX.current = e.clientX;
onResize(delta);
},
[onResize]
);
const handlePointerUp = useCallback(
(e: React.PointerEvent) => {
if (!isDragging.current) return;
isDragging.current = false;
(e.currentTarget as HTMLElement).releasePointerCapture(e.pointerId);
document.body.style.cursor = "";
document.body.style.userSelect = "";
onResizeEnd?.();
},
[onResizeEnd]
);
return (
<div
onMouseDown={handleMouseDown}
onPointerDown={handlePointerDown}
onPointerMove={handlePointerMove}
onPointerUp={handlePointerUp}
className={cn(
"group relative z-10 flex w-1 shrink-0 cursor-col-resize items-center justify-center",
"group relative z-10 flex w-1 shrink-0 cursor-col-resize items-center justify-center touch-none",
side === "left" ? "-ml-0.5" : "-mr-0.5"
)}
>