xterm.js在Web端实现Terminal终端的完整指南
本文详解如何在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终端的容器自适应、样式配置修改及组件销毁等高级操作,请参阅本站后续相关文章。
React.js 新手入门:环境搭建与第一个组件开发
2026-11-03 19:40:05
怎么在 UmiJS 中管理全局状态和数据流
2026-11-02 09:23:50
React表单处理:控制与非控制组件实战指南
2026-11-01 04:11:20
JavaScript 使用 showdown 实现 markdown 预览功能
2026-10-31 11:28:47
前后端分离架构下,JavaScript与JSP的角色演变及替代方案
2026-10-30 18:41:20







