网页版的终端,首选 xterm.js,其次是 k9s,和后端的通信采用 websocket 通信协议,这是一种可以在单个TCP连接上进行全双工通信的协议。如果需要websocket 带 token 发起连接可以参考这篇文章。
网页终端实现效果如下:

如果想要达到这种效果,那就跟着接下来的步骤一步步操作。

准备工作

1. 安装xterm

yarn add xterm

2. 安装xterm-addon-fit

yarn add xterm-addon-fit

xterm.js的插件,使终端的尺寸适合包含元素。

3. 安装xterm-addon-attach

yarn add xterm-addon-attach

xterm.js的附加组件,用于附加到Web Socket

前端实现

模板部分:

<template><div ><div ref="terminal" /></div>
</template>

业务逻辑部分:

<script>
import 'xterm/css/xterm.css'
import { Terminal } from 'xterm'
import { FitAddon } from 'xterm-addon-fit'
import { AttachAddon } from 'xterm-addon-attach'export default {name: 'terminal',data() {return {term: null,socketUri: 'ws://127.0.0.1:8088/podname',socket: '',accessToken: 'token',}},mounted() {this.initTerm();},beforeDestroy() {this.socket && this.socket.close();this.term && this.term.dispose();},methods: {initTerm() {// 1.xterm终端初始化const term = new Terminal({rendererType: "canvas", //渲染类型rows: 40, //行数cols: 100, // 不指定行数,自动回车后光标从下一行开始convertEol: true, //启用时,光标将设置为下一行的开头// scrollback: 50, //终端中的回滚量disableStdin: false, //是否应禁用输入windowsMode: true, // 根据窗口换行cursorStyle: "underline", //光标样式cursorBlink: true, //光标闪烁theme: {foreground: "#ECECEC", //字体background: "#000000", //背景色cursor: "help", //设置光标lineHeight: 20,},});// 2.webSocket初始化if (this.socketUri === '') return;this.socket = new WebSocket(this.socketUri, this.accessToken);    // 带 token 发起连接// 3.websocket集成的插件,这里要注意,网上写了很多websocket相关代码.xterm4版本没必要.const attachAddon = new AttachAddon(this.socket);const fitAddon = new FitAddon() // 全屏插件term.loadAddon(attachAddon);term.loadAddon(fitAddon);term.open(this.$refs.terminal);fitAddon.fit();term.focus();this.term = term;}}
}
</script>

注意事项

由于我们用的是 xterm4.x 的版本,它集成了 websocket 的很多功能,所以不需要写 websocket 的太多代码。
业务逻辑::

  • 将前端输出的任何东西不加处理全部通过websocket传到后端,后端根据前端的字符进行判断处理,再发送回前端进行显示.
  • xterm 就相当于是把每一步操作都发给后台,后台也同时把每一个操作去发给 ssh,相当于在 ssh 上做同步操作。
  • 每一步操作,都由websocket发给后台,后台再将每一步操作通过ssh去发给终端,最后就是同步终端操作命令。
  • 切记:前端不要做任何处理。我们不必关心用户输入与想做的操作,只需要向后台传递参数就好。

补充:删除的纯前端解决方案

测试的时候发现,按 Backspace 键删除字符的时候,总是会报错:

xterm.js: Parsing error:  {position: 0, code: 127, currentState: 0, collect: 0, params: e, …}

这个删除是返回的event,前端这边是可以进行一个事件监听,来单独做处理的。
解决方案如下:

term.onKey(e => {// back 删除的情况if (e.domEvent.keyCode === 8) { if (term._core.buffer.x > 2) {term.write(' ');}}
})

这个删除是我在纯前端测试的时候发现的问题,然后就这样解决了,实际上在与后端websocket链接之后就不会有这个问题的,你的删除指令发到后台,后台去将信息返回,然后你将信息write,就不会有这个问题了,就可以直接使用 onData() 即可。

xterm v4.13.0文档

安装

npm install --save xterm

使用

 import 'xterm/css/xterm.css'import { Terminal } from 'xterm'const term = new Terminal()term.open(document.getElementById('terminal'))

配置项

/*** 当 canvas 渲染器运行过慢时,会回退为 DOM 渲染器* DOM 渲染器下不起作用的功能: Letter spacing || Cursor blin*/
rendererType?: 'dom' || 'canvas'; // 渲染器类型cols?: number; // 列数
rows?: number; // 行数disableStdin?: boolean; // 是否禁用输入fontSize?: number; // 字体大小
fontFamily?: string; // 字体类型
fontWeight?: 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' | number; // 字体加粗
fontWeightBold?:  'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' | number; // 字体加粗
letterSpacing?: number; // 字符间距
lineHeight?: number; // 字体行高scrollback?: number; // 终端中的回滚量,即当前视口之上保留的行数
scrollSensitivity?: number; // 正常滚动的滚动速度
fastScrollModifier?: 'alt' | 'ctrl' | 'shift' | undefined; // 按住哪个键可倍增滚动速度
fastScrollSensitivity?: number; // 快速滚动的滚动速度logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'off'; 日志类型, 默认是 info
allowTransparency?: boolean; // 背景是否应支持非不透明颜色,开启后支持 theme中使用 rgba
theme?: {  // 主题cursor?: string; // 光标颜色cursorAccent?: string; // 光标的强调色foreground?: string; // 默认的前景色,即字体颜色background?: string; // 默认的背景色selection?: string; // 选择的背景色(可以是透明的)// 颜色: 使用 ANSI 编码black?: string; // `x1b[30m`red?: string; // `x1b[31m`green?: string; // `x1b[32m`yellow?: string; // `x1b[33m`blue?: string; // `x1b[34m`magenta?: string; // `x1b[35m`cyan?: string; // `x1b[36m`white?: string; // `\x1b[37m`brightBlack?: string; // `\x1b[1;30m`brightRed?: string; // `\x1b[1;31m`brightGreen?: string; // `\x1b[1;32m`brightYellow?: string; // `\x1b[1;33m`brightBlue?: string; // `\x1b[1;34m`brightMagenta?: string; // `\x1b[1;35m`brightCyan?: string; // `\x1b[1;36m`brightWhite?: string; // `\x1b[1;37m`
};bellStyle?: 'none' | 'sound'; // 终端将使用的铃声通知类型
bellSound?: string; // 当 bellStyle='sound' 时,用于 sound 的数据URIconvertEol?: boolean; // 启用时,光标将设置为每一新行下一行的开头
cursorBlink?: boolean; // 光标是否闪烁
cursorStyle?: 'block' | 'underline' | 'bar'; // 光标的样式
cursorWidth?: number; // cursorStyle='bar' 时光标的宽度(以px为单位)
altClickMovesCursor?: boolean; // 如果启用,alt+click会将提示光标移动到鼠标下方的位置。默认值为true/*** 终端中文本的最小对比度,设置该值将根据是否满足对比度动态更改前景颜色* Example values:* - 1: The default, do nothing.* - 4.5: WCAG AA合规性的最低要求* - 7: WCAG AAA合规性的最低要求* - 21: 黑纸白字或白纸黑字*/
minimumContrastRatio?: number;
drawBoldTextInBrightColors?: boolean; // 是否以明亮的颜色绘制粗体文本。默认值为true
wordSeparator?: string; // 字符被双击的时候单独被选中,多个字符可以用空格间隔
rightClickSelectsWord?: boolean; // 是否支持鼠标右键选中整行
screenReaderMode?: boolean; // 是否启用屏幕阅读器支持allowProposedApi?: boolean; // 是否允许使用建议的API, 如果为false,则任何标记为实验性/建议性的API的使用都将抛出错误
/*** Whether holding a modifier key will force normal selection behavior,* regardless of whether the terminal is in mouse events mode. This will* also prevent mouse events from being emitted by the terminal. For* example, this allows you to use xterm.js' regular selection inside tmux* with mouse mode enabled.* 无论终端是否处于鼠标事件模式,按住修改器键是否将强制执行正常选择行为。这也将防止终端发出鼠标事件。例如,这允许您在启用鼠标模式的情况下在tmux中使用xterm.js的常规选择。*/
macOptionClickForcesSelection?: boolean;
linkTooltipHoverDuration?: number; // 在链接上悬停时触发链接工具提示事件之前的持续时间(毫秒),将被弃用
macOptionIsMeta?: boolean; // 是否将选项视为元键
tabStopWidth?: number; // 终端中制表位的大小
/*** 是否启用“Windows模式”。由于Windows后端winpty和conpty通过在其一侧进行换行操作,因此xterm.js无法访问换行。* Whether "Windows mode" is enabled. Because Windows backends winpty and* conpty operate by doing line wrapping on their side, xterm.js does not* have access to wrapped lines. When Windows mode is enabled the following* changes will be in effect:* - Reflow is disabled.* - Lines are assumed to be wrapped if the last character of the line is*   not whitespace.*/
windowsMode?: boolean;
/*** 启用各种窗口操作和报告功能。* 出于安全原因,默认情况下禁用所有功能。*/
windowOptions?: IWindowOptions;

内置函数 Apis

open(HTMLElement): void; // Terminal基于传入的 dom 元素进行初始化
dispose(): void; // Terminal销毁,同时也会销毁 dom 元素以及事件
reset(): void; // Terminal  resetgetOption(key: string): any; // 获取配置
setOption(key: string, value: any): void; // 动态设置配置focus(): void; // Terminal聚焦
blur(): void; // Terminal失焦
resize(columns: number, rows: number): void; // 可以动态设置行数和列数write(data: string | Uint8Array, callback?: () => void): void; // xterm终端写入
writeln(data: string | Uint8Array, callback?: () => void): void;
writeUtf8(data: Uint8Array, callback?: () => void): void;
clear(): void; // 清空光标所在行上面的所有输入内容,不包含删除当前光标所在行select(column: number, row: number, length: number): void; // 选择第row + 1 行的 第 column + 1 列开始,直到后面的第 length 个字符
selectAll(): void; // 选中全部内容
selectLines(start: number, end: number): void; // 可以配合 onRender 方法的回调选中
hasSelection(): boolean; // 判断有没有选中
getSelection(): string; // 获取选中的字符
getSelectionPosition(): {startColumn: number, startRow: number, endColumn: number, endRow: number} | undefined; // 获取选中的字符的位置
clearSelection(): void; // 清除选中状态scrollLines(amount: number): void; // 一次滚动 amount 行
scrollPages(pageCount: number): void; // 相当于鼠标滚轮滑了pageCount下
scrollToTop(): void; // 滚动到顶部
scrollToBottom(): void; // 滚动到底部
scrollToLine(line: number): void; // 滚动到第 line + 1 行是当前窗口的第一行refresh(start: number, end: number): void; // 范围内 refresh
loadAddon(addon: ITerminalAddon): void; // 挂载插件// 以下均无测试使用
paste(data: string): void; // 用了,没啥反应
registerMarker(cursorYOffset: number): IMarker | undefined; // 注册标记,不会用
addMarker(cursorYOffset: number): IMarker | undefined; // 添加标记,不会用attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void; // 键盘的自定义事件
registerLinkMatcher(regex: RegExp, handler: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): number;
deregisterLinkMatcher(matcherId: number): void;
registerLinkProvider(linkProvider: ILinkProvider): IDisposable;registerCharacterJoiner(handler: (text: string) => [number, number][]): number;
deregisterCharacterJoiner(joinerId: number): void;

响应事件 callback

onKey(callback({ key: string, domEvent: KeyboardEvent })) // key: 键盘按键的值,domEvent: 键盘事件
onData(callback(key: String)) // 类似于input的oninput事件,key代表的是输入的字符
onCursorMove(callback()) // 输入光标位置变动会触发,比如输入,换行等
onLineFeed(callback()) // 操作回车按钮换行时触发,自然输入换行不会触发
onScroll(callback(scrollLineNumber: number)) // 当输入的行数超过设定的行数后会触发内容的滚动,输入换行以及回车换行均会触发
onSelectionChange(callback()) // 操作鼠标左键选中/取消选中会触发
onRender(callback({start: number, end: number})) // 鼠标移出点击,移入点击以及输入模式下键盘按下都会触发,范围从“0”到“Terminal.rows-1”
onResize(callback({cols: number, rows: number})) // 在 open() 之后如果调用 resize 设置行列会触发改事件,返回新的行列数值onTitleChange(callback()) // 标题更改触发,未找到对应的触发条件
onBell(callback()) // 为触发铃声时添加事件侦听器

基于 xterm + websocket + vue 实现网页版终端 terminal相关推荐

  1. 基于svelte3+sass仿微信网页版聊天|svelte.js 桌面聊天实例SvelteWebChat

    svelte-webchat:基于svelte3+svelteKit仿微信mac网页版聊天实战案例. 采用了最新前端svelte.js框架,基于svelte3+svelteKit+sass+svelt ...

  2. 网页版2048html制作,基于HTML+CSS+JS的网页版2048的实现

    ELECTRONICS WORLD·j6: 雾 与 粤 赛 基 于HTM L+CSS+J S的网页:I~2 048的实现 [摘要 ]描述了一个使用HTML和css进行uI界面设计,使用Js进行后台逻辑 ...

  3. 基于Vue的网页版录音并播放

    最近项目中需要实现一个效果,需要在网页上录制音频,并上传给后台,后续还需要做语音识别处理. 下面的表格罗列了我的前端项目中所使用的框架以及插件(本项目基于Vue): 插件名称 资源地址 Element ...

  4. 网页版终端webssh2配置

    开源项目webssh2可以实现浏览器访问终端,参照网上教程实践后,记录步骤如下: 安装NVM curl -o- https://raw.githubusercontent.com/creationix ...

  5. javascript mysql 知乎_GitHub - JobsDong/zhihudaily: 基于tornado,sae的网页版知乎日报

    修改配置文件config.py: # 配置数据存储引擎(基于kvdb, mysql)由于数据库需要租金,建议使用kvdb from base.daily_store import DailyStore ...

  6. 【终极之战】基于Vue3+Vant3造一个网页版的类掘金app项目 - 个人主页

    布局分析 第一件事还是布局分析,如上图所示该页面分为3个模块:个人信息模块.徽章模块和内容模块.其中个人信息模块头像信息,用户名,用户等级,所佩戴的徽章以及关注相关的信息和当前掘力值.这些基本信息在我 ...

  7. 网页版2048html制作,基于HTML+CSS+JS的网页版2048的实现.pdf

    ELECTRONICS WORLD ・探索与观察 基于HTML+CSS+JS的网页版2048的实现 山西农业大学 王艺燕 [摘要] 描述了一个使用HTML和CSS进行UI界面设计,使用JS进行后台逻辑 ...

  8. jquery 背景特效实现_html5实现的仿网页版微信聊天界面效果源码

    码农那点事儿 关注我们,一起学习进步 这是一款基于html5实现的仿网页版微信聊天界面效果源码,可实现微信网页版聊天界面效果,在编辑框编辑文字之后按Ctrl+Enter键即可提交文字到聊天对话框上.整 ...

  9. 基于 SpringBoot + Vue 框架开发的网页版聊天室项目

    ‍ ‍简介 微言聊天室是基于前后端分离,采用SpringBoot+Vue框架开发的网页版聊天室.使用了Spring Security安全框架进行密码的加密存储和登录登出等逻辑的处理,以WebSocke ...

最新文章

  1. pd.read_csv读取txt时整型变成浮点型问题解决
  2. java开发五年多少钱,附超全教程文档
  3. [YTU]_2475( C++习题 多重继承)
  4. Android开发中目前流行控件和知识点总结
  5. 华为面向全球发布HMS Core 4.0意味着什么?
  6. ubuntu20.04系统 ros noetic下安裝orbslam2
  7. 崩坏3区号+86_86,中国大陆国际区号是“ +86”,还是“ +086”、“ +0086”
  8. matlab 最速下降,matlab最速下降法
  9. Ubuntu 20.4 安装 Notepad++
  10. CISCO Nexus 系列交换机配置命令
  11. android学习---开发Google地图应用程序
  12. 给定一个无重复元素的数组 candidates 和一个目标数 target .
  13. 代写演讲稿的写作要求有哪些
  14. java 输入一个时间,获取当前周的周一以及周五时间【自然周】
  15. 决斗吧4G LTE:联发科helio步步紧逼,高通裁员步步惊心---国际电子商情
  16. 2021年中国中药创新药行业市场现状分析,医保中药扶持逐渐加强「图」
  17. 教妹学Java(一):什么是Java?
  18. 2.2 STM32 RAM溢出分析(KEIL在Build的时候提示Error:L6406E:No space in execution)
  19. java pdfbox2 中文乱码_Java用pdfbox或icepdf转换PDF为图片时,中文乱码问题
  20. 不容错过的千人盛会!2017 C3安全峰会看点抢先知

热门文章

  1. windows自带Bitlocker使用问题汇总
  2. 【fpga】gtx/gth概述
  3. Live800:回复慢十秒流量往外跑,客服不应答推广费白花
  4. 解压上传zip文件并获取excel表数据
  5. 独家 | 19年NAACL纪实:自然语言处理的实用性见解
  6. 无线路由器被蹭网后,有被黑的风险吗?
  7. 我们的征途是星辰大海 ( 蓝桥杯~算法提高 )
  8. Programming tools
  9. 长沙理工计算机竞赛黑马,2018年五大学科成绩出炉,长沙杀出一匹黑马!
  10. linux怎么强制解挂,linux下强制卸载挂接点——umount+Fuser命令详解