xterm.js在Web端实现Terminal终端的完整指南

作者:组件日常时间:2026-10-25 22:35:43浏览:549

本文详解如何在Web端利用xterm.js实现终端功能,通过React封装Xterminal组件,结合WebSocket与后端交互。内容涵盖组件初始化、数据渲染、键盘输入监听及父子组件通信,提供从安装到核心逻辑实现的完整代码示例,帮助开发者快速构建便捷的Web终端应用。

快速上手

在许多企业内部系统中,为了提升用户体验,往往需要在Web页面中集成终端功能。用户无需通过SSH连接,直接登录网站即可使用命令行工具,操作更加便捷。实现这一功能的关键技术之一是引入xtermjs库。

xterm是一个基于TypeScript开发的前端终端组件,能够在浏览器环境中直接运行命令行应用。它兼容大多数终端程序,如bash、vim和tmux,支持基于curses的应用程序及鼠标事件。此外,xterm.js具备极高的运行速度,并内置了GPU加速渲染器以优化显示效果。

  • 关于xtermjs的详细API文档,可访问官方文档:xtermjs.org/docs/api/te…
  • 部分API的中文介绍参考链接:https://www.jb51.net/article/266450.htm

在绝大多数应用场景中,xtermjs通过WebSocket与后端服务器建立通信连接。用户在前端的每一次按键输入都会被发送至后端,后端处理后将响应数据返回,前端负责将这些数据渲染到终端界面中。

鉴于本文示例使用的开发框架为React,后续的功能实现均基于React环境进行。

快速上手

npm install xterm

考虑到该终端功能可能在多个页面复用,我们将其单独封装为一个独立组件,命名为Xterminal。

import {memo, useEffect, useRef} from "react";
import {Terminal} from "xterm"
import type {ITerminalOptions, ITerminalInitOnlyOptions} from "xterm"
import "xterm/css/xterm.css"
interface Props {
    options?: ITerminalOptions & ITerminalInitOnlyOptions,  // 定制化配置参数
    onInput: (value: string) => void
}
const defaultOptions = {
    cols: 20,
    rows: 10
}
function Xterminal(props: Props) {
    const {onInput} = props
    const terminalRef = useRef<null | HTMLDivElement>(null)
    useEffect(() => {
        const options = {...defaultOptions, ...props.options}
        const term = new Terminal(options);
        // 打开一个已经初始化好的的终端
        term.open(terminalRef.current as HTMLDivElement);
        // 向终端中写入数据
        term.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ')
        term.onData((value) => {
            onInput(value)
            term.write(value)
        })
    }, [])
    return (
        <div className="terminal-container">
            <div ref={terminalRef}></div>
        </div>
    )
}
export default memo(Xterminal)

将该组件引入到App主文件中后,即可看到一个初始化完成的Web终端界面。

快速上手

接下来,我们将逐步完善终端的各项细节功能。

首次建立链接

当WebSocket连接首次建立时,后端通常会返回一段初始默认数据。此时,我们需要在组件初始化完成后,将这些数据渲染出来,而不是随意写入一些测试字符串。

interface Props {
    options?: ITerminalOptions & ITerminalInitOnlyOptions,  // 定制化配置参数
    code: string | Uint8Array,
    onInput: (value: string) => void
}
const defaultOptions = {
    cols: 20,
    rows: 10
}
function Xterminal(props: Props) {
    const {code, onInput} = props
    const terminalRef = useRef<null | HTMLDivElement>(null)
    const options = useMemo(() => {
        return {...defaultOptions, ...props.options}
    }, [props.options])
    const termRef = useRef<Terminal>(new Terminal(options))
    useEffect(() => {
        // 打开一个已经初始化好的的终端
        termRef.current.open(terminalRef.current as HTMLDivElement);
        // 向终端中写入数据
        termRef.current.onData((value) => {
            onInput(value)
            termRef.current.write(value)
        })
    }, [])
    // 监听code的变化,然后每次接收到响应的时候就写入
    useEffect(() => {
        termRef.current.write(code)
    }, [code])
    return (
        <div className="terminal-container">
            <div ref={terminalRef}></div>
        </div>
    )
}

注意:由于终端实例需要在不同位置复用,因此将其存储在Ref中。请留意此处代码与前述基础代码的区别。

处理输入逻辑

键盘输入事件的监听需要使用onData监听函数,该函数能够捕获用户输入的每一个字符。

useEffect(() => {
+   termRef.current.onData((value) => {
+        console.log(value)
+        termRef.current.write(value)
+     })
}, [])

在onData事件处理中,我们需要与后端进行交互,因此必须将输入的value传递给父组件,由父组件发起网络请求。

useEffect(()=>{
    term.current.onData((value) => {
        onInput(value)
        termRef.current.write(value)
    })
},[])

快速上手

父组件中的onInput负责处理与后端的具体交互逻辑。至此,一个基础的Web Terminal功能已基本实现。

关于Web终端的容器自适应、样式配置修改及组件销毁等高级操作,请参阅本站后续相关文章。

作者最新文章
相关文章
更多