From 9aaa1eaf07c78ae54f214fd240c7895f95d15420 Mon Sep 17 00:00:00 2001 From: Ethanfly Date: Wed, 31 Dec 2025 15:58:33 +0800 Subject: [PATCH] fix: use DOM event listener with stopPropagation to prevent multiple tab closures --- src/App.js | 9 +-------- src/components/Terminal.js | 26 +++++++++++++++++++------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/App.js b/src/App.js index 1a3bd9f..a511c39 100644 --- a/src/App.js +++ b/src/App.js @@ -84,13 +84,6 @@ function App() { e.preventDefault(); setShowCommandPalette(true); } - // Ctrl+W: 关闭当前标签页 - if ((e.ctrlKey || e.metaKey) && e.key === 'w') { - e.preventDefault(); - if (activeTabId) { - closeTab(activeTabId); - } - } // Escape: 关闭弹窗 if (e.key === 'Escape') { setShowCommandPalette(false); @@ -101,7 +94,7 @@ function App() { window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); - }, [activeTabId, closeTab]); + }, []); // 连接主机 const connectHost = useCallback((host) => { diff --git a/src/components/Terminal.js b/src/components/Terminal.js index 95d3d92..05e7205 100644 --- a/src/components/Terminal.js +++ b/src/components/Terminal.js @@ -22,6 +22,7 @@ function Terminal({ tabId, hostId, isActive, onConnectionChange, onShowCommandPa const contextMenuHandlerRef = useRef(null); const resizeTimeoutRef = useRef(null); const webglAddonRef = useRef(null); + const keydownHandlerRef = useRef(null); const onConnectionChangeRef = useRef(onConnectionChange); onConnectionChangeRef.current = onConnectionChange; @@ -234,31 +235,36 @@ function Terminal({ tabId, hostId, isActive, onConnectionChange, onShowCommandPa } }); - // 自定义按键处理 - 拦截 Ctrl+W 和 Ctrl+K(仅当前活动标签页响应) - term.attachCustomKeyEventHandler((e) => { + // 在容器上添加键盘事件监听器(捕获阶段),确保能拦截并阻止事件冒泡 + keydownHandlerRef.current = (e) => { // 只有活动标签页才响应快捷键 if (!isActiveRef.current) { - return true; + return; } // Ctrl+W: 关闭当前标签页 if ((e.ctrlKey || e.metaKey) && e.key === 'w') { e.preventDefault(); + e.stopPropagation(); + e.stopImmediatePropagation(); if (onCloseTabRef.current) { onCloseTabRef.current(); } - return false; // 阻止 xterm 处理 + return; } // Ctrl+K: 打开命令面板 if ((e.ctrlKey || e.metaKey) && e.key === 'k') { e.preventDefault(); + e.stopPropagation(); + e.stopImmediatePropagation(); if (onShowCommandPaletteRef.current) { onShowCommandPaletteRef.current(); } - return false; + return; } - return true; // 允许 xterm 处理其他按键 - }); + }; + // 使用捕获阶段确保在 xterm 处理之前拦截 + container.addEventListener('keydown', keydownHandlerRef.current, true); // 选中自动复制到剪贴板 term.onSelectionChange(() => { @@ -344,6 +350,12 @@ function Terminal({ tabId, hostId, isActive, onConnectionChange, onShowCommandPa contextMenuHandlerRef.current = null; } + // 清理键盘事件监听器 + if (keydownHandlerRef.current && terminalRef.current) { + terminalRef.current.removeEventListener('keydown', keydownHandlerRef.current, true); + keydownHandlerRef.current = null; + } + if (cleanupListenersRef.current) { cleanupListenersRef.current(); cleanupListenersRef.current = null;