diff --git a/package-lock.json b/package-lock.json index 825690b..5d0fba2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@capacitor/status-bar": "^5.0.6", "@xterm/addon-fit": "^0.10.0", "@xterm/addon-web-links": "^0.11.0", + "@xterm/addon-webgl": "^0.19.0", "@xterm/xterm": "^5.5.0", "electron-store": "^8.1.0", "framer-motion": "^10.16.16", @@ -5866,6 +5867,12 @@ "@xterm/xterm": "^5.0.0" } }, + "node_modules/@xterm/addon-webgl": { + "version": "0.19.0", + "resolved": "https://registry.npmmirror.com/@xterm/addon-webgl/-/addon-webgl-0.19.0.tgz", + "integrity": "sha512-b3fMOsyLVuCeNJWxolACEUED0vm7qC0cy4wRvf3oURSzDTYVQiGPhTnhWZwIHdvC48Y+oLhvYXnY4XDXPoJo6A==", + "license": "MIT" + }, "node_modules/@xterm/xterm": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz", diff --git a/package.json b/package.json index 13a5e0b..9a13151 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "@capacitor/status-bar": "^5.0.6", "@xterm/addon-fit": "^0.10.0", "@xterm/addon-web-links": "^0.11.0", + "@xterm/addon-webgl": "^0.19.0", "@xterm/xterm": "^5.5.0", "electron-store": "^8.1.0", "framer-motion": "^10.16.16", diff --git a/src/components/Terminal.js b/src/components/Terminal.js index a136eb3..f710098 100644 --- a/src/components/Terminal.js +++ b/src/components/Terminal.js @@ -3,6 +3,7 @@ import { motion } from 'framer-motion'; import { Terminal as XTerm } from '@xterm/xterm'; import { FitAddon } from '@xterm/addon-fit'; import { WebLinksAddon } from '@xterm/addon-web-links'; +import { WebglAddon } from '@xterm/addon-webgl'; import '@xterm/xterm/css/xterm.css'; import { FiCommand, FiRefreshCw, FiInfo, FiFolder, FiActivity, FiZap } from 'react-icons/fi'; @@ -19,6 +20,8 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT const hasConnectedRef = useRef(false); const resizeObserverRef = useRef(null); const contextMenuHandlerRef = useRef(null); + const resizeTimeoutRef = useRef(null); + const webglAddonRef = useRef(null); const onConnectionChangeRef = useRef(onConnectionChange); onConnectionChangeRef.current = onConnectionChange; @@ -154,8 +157,12 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT cursorStyle: 'bar', fontSize: 14, fontFamily: "'JetBrains Mono', 'Fira Code', Consolas, monospace", - lineHeight: 1.5, - scrollback: 2000, + lineHeight: 1.4, + scrollback: 1000, // 减少滚动缓冲区提升性能 + fastScrollModifier: 'alt', // 快速滚动 + fastScrollSensitivity: 5, + smoothScrollDuration: 0, // 禁用平滑滚动提升性能 + scrollSensitivity: 1, theme: { // 赛博朋克主题配色 background: '#050810', @@ -195,6 +202,19 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT xtermRef.current = term; fitAddonRef.current = fitAddon; + // 尝试加载 WebGL 渲染器提升性能 + try { + const webglAddon = new WebglAddon(); + webglAddon.onContextLoss(() => { + webglAddon.dispose(); + webglAddonRef.current = null; + }); + term.loadAddon(webglAddon); + webglAddonRef.current = webglAddon; + } catch (e) { + console.warn('WebGL 渲染器不可用,使用默认渲染器:', e); + } + setTimeout(() => { fitAddon.fit(); }, 0); @@ -229,8 +249,14 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT }; container.addEventListener('contextmenu', contextMenuHandlerRef.current); + // 使用防抖的 ResizeObserver 避免频繁调用 resizeObserverRef.current = new ResizeObserver(() => { - fitTerminal(); + if (resizeTimeoutRef.current) { + clearTimeout(resizeTimeoutRef.current); + } + resizeTimeoutRef.current = setTimeout(() => { + fitTerminal(); + }, 100); // 100ms 防抖 }); resizeObserverRef.current.observe(container); @@ -268,6 +294,10 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT clearTimeout(initTimerRef.current); } + if (resizeTimeoutRef.current) { + clearTimeout(resizeTimeoutRef.current); + } + if (resizeObserverRef.current) { resizeObserverRef.current.disconnect(); resizeObserverRef.current = null; @@ -289,6 +319,12 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT connectionIdRef.current = null; } + // 清理 WebGL 渲染器 + if (webglAddonRef.current) { + webglAddonRef.current.dispose(); + webglAddonRef.current = null; + } + if (xtermRef.current) { xtermRef.current.dispose(); xtermRef.current = null; @@ -329,15 +365,13 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT setTimeout(() => connect(), 100); }, [connect]); - // 工具栏按钮组件 + // 工具栏按钮组件 - 简化动画提升性能 const ToolButton = ({ onClick, disabled, active, title, children }) => ( - {children} - + ); return (
- {/* 背景装饰 */} -
-
-
+ {/* 简化背景装饰以提升性能 */} +
{/* 终端工具栏 */}
@@ -383,10 +415,8 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT
) : connectionId ? (
- CONNECTED @@ -403,16 +433,14 @@ function Terminal({ tabId, hostId, onConnectionChange, onShowCommandPalette, onT {/* 右侧工具按钮 */}
{/* 命令提示 */} - COMMANDS - +