xterm.js 官网
借鉴学习案例
一. 筹备工作
- npm install xterm
-
npm install xterm-addon-fit
二. 初始引入渲染
import {Terminal} from 'xterm' import {FitAddon} from 'xterm-addon-fit' import 'xterm/css/xterm.css' let term = new Terminal({ // 渲染类型 rendererType: 'canvas', // 是否禁用输出 disableStdin: false, cursorStyle: 'underline', // 启用时光标将设置为下一行的结尾 convertEol: true, // 终端中的回滚量 scrollback: 10, fontSize: 14, rows: 20, // 光标闪动 cursorBlink: true, theme: { // 字体 foreground: '#ffffff', background: '#000000', // 光标 cursor: 'help', lineHeight: 18, }, }) // 换行并输出起始符 $ term.prompt = () => {term.write(`\r\n${terminalTitleTemplate}:`) } // 进行适应容器元素大小 let fitAddon = new FitAddon() term.loadAddon(fitAddon) fitAddon.fit()
三. 重点来了,onData 的应用能够输出中文且按高低键应用历史命令的时候不会光标串行笼罩之前的终端提示符
const keyAction = (){ // 定义变量获取整行数据 let currentLineData = '' // 历史行输出数据 let historyLineData = [] let last = 0 // 使其可能输出汉字 term.onData(async key => { //enter 键 if (key.charCodeAt(0) === 13) { // 将行数据进行增加进去 if (currentLineData !== '') { // 将以后行数据传入历史命令数组中存储 historyLineData.push(currentLineData) // 定义以后行命令在整个数组中的地位 last = historyLineData.length - 1 } // 当输出 clear 时清空终端内容 if (currentLineData === 'clear') {term.clear() } // 在这能够进行发动申请将整行数据传入 // 清空以后行数据 currentLineData = '' term.write(`\r\n${terminalTitleTemplate}: `) } else if (key.charCodeAt(0) === 127) { // 删除键 --》以后行偏移量 x 大于终端提示符所占地位时进行删除 if (term._core.buffer.x > terminalTitleTemplate.length + 1) {currentLineData = currentLineData.slice(0, -1) term.write('\b \b') } } else if (key === '\u001b[A') { //up 键的时候 let len = 0 if (historyLineData.length > 0) {len = historyLineData.length + 1} if (last < len && last > 0) { // 以后行有数据的时候进行删除掉在进行渲染上存储的历史数据 for (let i = 0; i < currentLineData.length; i++) {if (term._core.buffer.x > terminalTitleTemplate.length + 1) {term.write('\b \b') } } let text = historyLineData[last - 1] term.write(text) // 重点,肯定要记住存储以后行命令保障下次 up 或 down 时不会光标错乱笼罩终端提示符 currentLineData = text last-- } } else if (key === '\u001b[B') { //down 键 let lent = 0 if (historyLineData.length > 0) {lent = historyLineData.length - 1} if (last < lent && last > -1) {for (let i = 0; i < currentLineData.length; i++) {if (term._core.buffer.x > terminalTitleTemplate.length + 1) {term.write('\b \b') } } let text = historyLineData[last + 1] term.write(text) currentLineData = text last++ } } else { // 啥也不做的时候就间接输出 currentLineData += key term.write(key) } }) }
四. 渲染执行
useEffect(() => {
// 创立实例
term.open(document.getElementById('ter'))
// 初始化
term._initialized = true
term.prompt()
// 进行适应容器元素大小
term.loadAddon(fitAddon)
fitAddon.fit()
term.focus()
keyAction()
return () => {term.dispose()
}
}, [])
return (
<>
{/* terminal 装载容器 */}
<div id="ter" />
</>
)