Vue xtermjs 终端

2023-12-14 14:37:27

Vue xtermjs 终端

安装步骤如下
安装xtermjs所需要的插件

npm install --save xterm
npm install --save xterm-addon-fit
npm install --save xterm-addon-attach

HTML代码片段

<template>
    <div>
      <a-drawer
        title="终端"
        placement="right"
        :closable="false"
        :visible="visible"
        :width="1000"
        @close="onClose"
      >
      <div id="xterm" class="xterm" style="height:800px" />
      </a-drawer>
    </div>
  </template>
  <script>
import "xterm/css/xterm.css";
import { Terminal } from "xterm";
import { FitAddon } from "xterm-addon-fit";
  export default {
    data() {
      return {
        visible: false,
        term: "",//terminal 黑窗口容器
			prefix: "[root@serverip ~]# ",//前缀
			inputText: "",//输入内容,每次回车后进行ws通信然后清空此数据
      };
    },
    methods: {
      //初始化黑窗口
		async initTerm() {
			const fitAddon = new FitAddon();
			this.term = new Terminal({
				fontSize: 14,
				cursorBlink: true,
				allowProposedApi: true,
				disableStdin: false,
				LogLevel: "debug",
			});

			this.term.loadAddon(fitAddon);
			//开启Xterm终端
			this.term.open(document.getElementById("xterm"));
			this.term.writeln("\x1b[1;1;32mwellcom to web terminal!\x1b[0m");
			this.term.write(this.prefix); //黑窗口 前缀

			await this.termPromt(); //term.promt
			await this.termKeyCode(); //事件

			fitAddon.fit(); //黑窗口适应实际div宽高
			this.term.focus(); //自动聚焦
		},
		//事件
		termKeyCode() {
			const TERMINAL_INPUT_KEY = {
				BACK: 8, // 退格删除键
				ENTER: 13, // 回车键
				UP: 38, // 方向盘上键
				DOWN: 40, // 方向盘键
				LEFT: 37, // 方向盘左键
				RIGHT: 39, // 方向盘右键
			};
			// const { eqpCode, server } = this.selectObj;
			let inputText = "";
			let currentIndex = 0;
			let inputTextList = [];
			this.term.onKey((e) => {
				const { key, domEvent } = e;
				const { keyCode, altKey, altGraphKey, ctrlKey, metaKey } = domEvent;

				const printAble = !(altKey || altGraphKey || ctrlKey || metaKey); // 禁止相关按键
				const totalOffsetLength = inputText.length + this.prefix.length; // 总偏移量
				const currentOffsetLength = this.term._core.buffer.x; // 当前x偏移量

				switch (keyCode) {
					//删除
					case TERMINAL_INPUT_KEY.BACK:
						if (currentOffsetLength > this.prefix.length) {
							const cursorOffSetLength = this.getCursorOffsetLength(totalOffsetLength - currentOffsetLength, "\x1b[D"); // 保留原来光标位置

							this.term._core.buffer.x = currentOffsetLength - 1;
							this.term.write("\x1b[?K" + inputText.slice(currentOffsetLength - this.prefix.length));
							this.term.write(cursorOffSetLength);
							inputText = `${inputText.slice(0, currentOffsetLength - this.prefix.length - 1)}${inputText.slice(
								currentOffsetLength - this.prefix.length
							)}`;
						}
						break;
					//回车
					case TERMINAL_INPUT_KEY.ENTER: {
						this.term.write("\r\n");
						console.log("inputText", inputText);
						//ws 通信参数
						// let wsParams = { EqpCode: eqpCode, Action: "terminal", Data: inputText };
						// this.$emit("websocketSend", wsParams, server);

						if (!inputText.trim()) {
							this.term.prompt();
							return;
						}

						if (inputTextList.indexOf(inputText) === -1) {
							inputTextList.push(inputText);
							currentIndex = inputTextList.length;
						}

						this.term.prompt();
						inputText = "";
						break;
					}

					case TERMINAL_INPUT_KEY.UP: {
						if (!inputTextList[currentIndex - 1]) break;

						const offsetLength = this.getCursorOffsetLength(inputText.length, "\x1b[D");

						inputText = inputTextList[currentIndex - 1];
						this.term.write(offsetLength + "\x1b[?K");
						this.term.write(inputTextList[currentIndex - 1]);
						this.term._core.buffer.x = totalOffsetLength;
						currentIndex--;

						break;
					}
					case TERMINAL_INPUT_KEY.LEFT:
						if (currentOffsetLength > this.prefix.length) {
							this.term.write(key); // '\x1b[D'
						}
						break;

					case TERMINAL_INPUT_KEY.RIGHT:
						if (currentOffsetLength < totalOffsetLength) {
							this.term.write(key); // '\x1b[C'
						}
						break;
					default: {
						// 在当前的坐标写上 key 和坐标后面的字符
						// 移动停留在当前位置的光标
						if (!printAble) break;
						if (totalOffsetLength >= this.term.cols) break;
						if (currentOffsetLength >= totalOffsetLength) {
							this.term.write(key);
							inputText += key;
							break;
						}
						let cursorOffSetLength = this.getCursorOffsetLength(totalOffsetLength - currentOffsetLength, "\x1b[D");
						this.term.write("\x1b[?K" + `${key}${inputText.slice(currentOffsetLength - this.prefix.length)}`);
						this.term.write(cursorOffSetLength);
						inputText = inputText.slice(0, currentOffsetLength) + key + inputText.slice(totalOffsetLength - currentOffsetLength);
						break;
					}
				}
			});
		},
		//限制和后端交互,只有输入回车键才显示结果
		termPromt() {
			this.term.prompt = () => {
				this.term.write(this.prefix);
			};
		},
		//获取光标当前位置
		getCursorOffsetLength(offsetLength, subString) {
			let cursorOffsetLength = "";
			for (let offset = 0; offset < offsetLength; offset++) {
				cursorOffsetLength += subString;
			}
			return cursorOffsetLength;
		},
		//写入黑窗口
		wirteTerm(data) {
			console.log("写入黑窗口", data);
			this.term.writeln(data);
			this.term.prompt();
		},
		//加载基础数据
		pageLoad(data) {
			this.selectObj = data;
			this.drawerFlag = true;
			this.$nextTick(() => {
				this.initTerm();
			});
		},
		cancelClick() {
			this.drawerFlag = false;
			//关闭弹框
			this.term.dispose(document.getElementById("xterm"));
		},
      showDrawer() {
        this.visible = true;
        this.$nextTick(()=>{
          this.initTerm()
        })
      },
      onClose() {
        this.visible = false;
      },
    },
  };
  </script>
  <style>
 #terminal{
    width:100%;
    height:800px;
 }
</style>

文章来源:https://blog.csdn.net/weixin_47000834/article/details/134994104
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。