From b1e6b0bfac526003c78edc2716b4efa27818adb3 Mon Sep 17 00:00:00 2001 From: 7418 <7418@openclaw.ai> Date: Fri, 27 Feb 2026 15:49:01 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=A2=84=E8=A7=88?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF=E6=8B=96=E6=8B=BD=E5=88=86=E9=9A=94=E7=BA=BF?= =?UTF-8?q?=E5=BF=AB=E9=80=9F=E7=A7=BB=E5=8A=A8=E6=97=B6=E5=AE=BD=E5=BA=A6?= =?UTF-8?q?=E4=B8=8D=E8=B7=9F=E6=89=8B=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因: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 --- src/components/layout/ResizeHandle.tsx | 56 ++++++++++++++------------ 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/src/components/layout/ResizeHandle.tsx b/src/components/layout/ResizeHandle.tsx index 3c77e26..76a4adf 100644 --- a/src/components/layout/ResizeHandle.tsx +++ b/src/components/layout/ResizeHandle.tsx @@ -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 (