一、Xterm.js 介紹
xterm 是一個使用 TypeScript 編寫的前端終端組件,可以直接在瀏覽器中實現一個命令行終端應用。Xterm.js 適用於大多數終端應用程序,如 bash,vim 和 tmux,這包括對基於curses的應用程序和鼠標事件的支持。Xterm.js 非常快,它甚至還包括一個GPU加速的渲染器。
這里有一些 api 介紹,可以看下先:Class: Terminal —— https://xtermjs.org/docs/api/terminal/classes/terminal/
這里有篇博客對這個 api 的一些翻譯:初窺Xterm.js —— https://juejin.cn/post/6844903809035010055
還有一篇博客可以看看:用 xterm.js 實現一個簡易的 web-terminal !—— https://juejin.cn/post/6918911964009725959
還有一篇博客有具體使用介紹:xterm.js + vue + websocket實現終端功能(xterm 3.x+xterm 4.x) —— https://blog.csdn.net/weixin_38318244/article/details/103908129
二、使用 xterm.js 開發終端流程
1、安裝依賴
// 1、安裝 xterm
npm install --save xterm // 2、安裝xterm-addon-fit // xterm.js的插件,使終端的尺寸適合包含元素。
npm install --save xterm-addon-fit // 3、安裝xterm-addon-attach(這個你不用就可以不裝) // xterm.js的附加組件,用於附加到Web Socket
npm install --save xterm-addon-attach
2、創建xterm實例並掛載到dom上
3、xterm全屏調整,讓終端的尺寸包含元素,要不然會有溢出的隱藏掉了,這樣包含讓終端內元素自適應。
4、具體代碼如下:
<template>
<div id="terminal" ref="terminal"></div>
</template>
<script> import { Terminal } from "xterm" import { FitAddon } from 'xterm-addon-fit' import "xterm/css/xterm.css" export default { data() { return { term: "", // 保存terminal實例
rows: 40, cols: 100 } }, mounted() { this.initXterm() }, methods: { initXterm() { let _this = this let term = new Terminal({ rendererType: "canvas", //渲染類型
rows: _this.rows, //行數
cols: _this.cols, // 不指定行數,自動回車后光標從下一行開始
convertEol: true, //啟用時,光標將設置為下一行的開頭 // scrollback: 50, //終端中的回滾量
disableStdin: false, //是否應禁用輸入 // cursorStyle: "underline", //光標樣式
cursorBlink: true, //光標閃爍
theme: { foreground: "#ECECEC", //字體
background: "#000000", //背景色
cursor: "help", //設置光標
lineHeight: 20 } }) // 創建terminal實例
term.open(this.$refs["terminal"]) // 換行並輸入起始符 $
term.prompt = _ => { term.write("\r\n\x1b[33m$\x1b[0m ") } term.prompt() // canvas背景全屏
const fitAddon = new FitAddon() term.loadAddon(fitAddon) fitAddon.fit() window.addEventListener("resize", resizeScreen) function resizeScreen() { try { // 窗口大小改變時,觸發xterm的resize方法使自適應
fitAddon.fit() } catch (e) { console.log("e", e.message) } } _this.term = term _this.runFakeTerminal() }, runFakeTerminal() { let _this = this let term = _this.term if (term._initialized) return
// 初始化
term._initialized = true term.writeln("Welcome to \x1b[1;32m墨天輪\x1b[0m.") term.writeln('This is Web Terminal of Modb; Good Good Study, Day Day Up.') term.prompt() // 添加事件監聽器,支持輸入方法
term.onKey(e => { const printable = !e.domEvent.altKey && !e.domEvent.altGraphKey && !e.domEvent.ctrlKey && !e.domEvent.metaKey if (e.domEvent.keyCode === 13) { term.prompt() } else if (e.domEvent.keyCode === 8) { // back 刪除的情況
if (term._core.buffer.x > 2) { term.write('\b \b') } } else if (printable) { term.write(e.key) } console.log(1,'print', e.key) }) term.onData(key => { // 粘貼的情況
if(key.length > 1) term.write(key) }) } } } </script>
效果如下:
這個就是純前端的輸入與write展示,在實際應用是需要xterm與websocket結合發送數據並顯示在屏幕上的
5、xterm與websocket結合發送數據並顯示在屏幕上
這個再寫篇單獨的博客記錄吧,見下篇博客。
三、遇到的問題
1、有2個問題見這篇博客:使用xterm報錯:Error: Terminal requires a parent element、及刪除時報錯:xterm.js: Parsing error 的問題
2、關於全屏
在這里我要吐槽一下這個xterm.js的官網,真是辣雞的很,什么都不寫清楚,就實例一下就完事了,好多參數和方法api里也不給個例子,還得自己到處去找,真的很辣雞!一開始以為4.0中不需要設置 fit 及 fullscreen,引入css后直接設置行數和列數就能實現背景鋪滿全屏。
但遇到一個問題是,xterm默認代碼不會占滿一整行,而是會直接換行,所以這里我們需要使用到官網首頁給到的插件。
import { FitAddon } from "xterm-addon-fit"; // canvas背景全屏-默認
var fitAddon = new FitAddon(); term.loadAddon(fitAddon); fitAddon.fit(); // 內容全屏顯示-窗口大小發生改變時
function resizeScreen(size) { console.log("size", size); try { fitAddon.fit(); // 窗口大小改變時觸發xterm的resize方法,向后端發送行列數,格式由后端決定
term.onResize(size => { _this.onSend({ Op: "resize", Cols: size.cols, Rows: size.rows }); }); } catch (e) { console.log("e", e.message); } } window.addEventListener("resize", resizeScreen);
3、關於字符刪除與上下鍵切換命令等
值得注意的是,在我們使用 xterm 實現仿終端功能時,不需要對輸入字符進行判斷,也不需要在輸入事件中把輸入的字符打出來。因為在輸入事件中執行的 websocket 連接中,每輸入一個字符都會自動傳到后端,而后端會根據你輸入的回車符來判斷是否要為你換行及返回何種數據。
也就是說:我們不必關心用戶輸入與想做的操作,只需要向后台傳遞參數就好。