移动端滚动按钮复用滚轮逻辑

This commit is contained in:
beibeizi committed 2026-03-16 16:31:44 +08:00
1 parent f51d33af83
commit 26d236fd8c
3 files changed
+45 -12

No files matched your search

+3 -12
View File
@@ -13,7 +13,7 @@ type MobileTab = "terminal" | "files" | "system";
export function TerminalMobile({ state, onBack }: TerminalMobileProps) {
const [activeTab, setActiveTab] = React.useState<MobileTab>("terminal");
const { syncTerminalSize, terminalInstance } = state;
const { syncTerminalSize, terminalInstance, scrollTerminal } = state;
React.useEffect(() => {
if (activeTab !== "terminal") {
@@ -27,15 +27,6 @@ export function TerminalMobile({ state, onBack }: TerminalMobileProps) {
term.focus();
}, [activeTab, syncTerminalSize, terminalInstance]);
const handleScroll = React.useCallback((direction: "up" | "down") => {
const term = terminalInstance.current;
if (!term) {
return;
}
const lines = direction === "up" ? -8 : 8;
term.scrollLines(lines);
}, [terminalInstance]);
const actions = [
{
key: "language",
@@ -151,7 +142,7 @@ export function TerminalMobile({ state, onBack }: TerminalMobileProps) {
<div className="absolute right-4 bottom-4 flex flex-col gap-2">
<button
type="button"
onClick={() => handleScroll("up")}
onClick={() => scrollTerminal("up")}
className={`h-10 w-10 rounded-full border text-base ${
state.isDark
? "border-slate-700 bg-slate-900/90 text-slate-200"
@@ -163,7 +154,7 @@ export function TerminalMobile({ state, onBack }: TerminalMobileProps) {
</button>
<button
type="button"
onClick={() => handleScroll("down")}
onClick={() => scrollTerminal("down")}
className={`h-10 w-10 rounded-full border text-base ${
state.isDark
? "border-slate-700 bg-slate-900/90 text-slate-200"
@@ -156,6 +156,7 @@ export function useTerminalSession(sessionId?: string) {
autoReconnect: socketState.autoReconnect,
setAutoReconnect: socketState.setAutoReconnect,
syncTerminalSize: socketState.syncTerminalSize,
scrollTerminal: socketState.scrollTerminal,
handleReconnect: socketState.handleReconnect,
handleCancelReconnect: socketState.handleCancelReconnect,
sessionInfo: sessionInfoState.sessionInfo,
@@ -247,6 +247,46 @@ export function useTerminalSocket({
const connectSocketRef = React.useRef(connectSocket);
const sendInputRef = React.useRef(sendInput);
const syncTerminalSizeRef = React.useRef(syncTerminalSize);
const scrollTerminal = React.useCallback((direction: "up" | "down") => {
const term = terminalInstance.current;
const container = terminalRef.current;
if (!term || !container) {
return;
}
if (term.modes.mouseTrackingMode !== "none") {
return;
}
const lineDelta = direction === "up" ? -8 : 8;
const sendTmuxWheelPage = (delta: number) => {
if (delta === 0) {
return;
}
const sequence = delta < 0 ? "\x1b[5~" : "\x1b[6~";
sendInput(sequence);
};
const activeBuffer = term.buffer.active;
const hasLocalScrollback = activeBuffer.type === "normal" && activeBuffer.baseY > 0;
if (!hasLocalScrollback) {
sendTmuxWheelPage(lineDelta);
return;
}
const viewport = container.querySelector<HTMLElement>(".xterm-viewport");
if (viewport) {
const maxScrollTop = Math.max(0, viewport.scrollHeight - viewport.clientHeight);
const isAtTop = viewport.scrollTop <= 0;
const isAtBottom = viewport.scrollTop >= maxScrollTop;
const isEnhancedSession = enhancedSessionRef.current;
if (isEnhancedSession && lineDelta < 0 && isAtTop) {
sendTmuxWheelPage(lineDelta);
return;
}
if (isEnhancedSession && lineDelta > 0 && isAtBottom) {
sendTmuxWheelPage(lineDelta);
return;
}
}
term.scrollLines(lineDelta);
}, [sendInput, enhancedSessionRef]);
React.useEffect(() => {
connectSocketRef.current = connectSocket;
@@ -461,6 +501,7 @@ export function useTerminalSocket({
autoReconnect,
setAutoReconnect,
syncTerminalSize,
scrollTerminal,
handleReconnect,
handleCancelReconnect,
};