当前位置: 首页 > 工具软件 > Xterm.js > 使用案例 >

xterm.js4 Vue版本实现

洪飞龙
2023-12-01

基于xterm.js 实现Vue版本终端terminal
npm install --save xterm

npm install --save xterm-addon-fit

xterm-addon-attach

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

npm install --save xterm-addon-attach

<template>
    <div id="xterm" class="xterm" />
</template>
import { Terminal } from 'xterm'
import { FitAddon } from 'xterm-addon-fit'
<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: 'Xterm',
  props: {
    socketURI: {
      type: String,
      default: ''
    },
  },
 watch: {
    socketURI: {
      deep: true, //对象内部属性的监听,关键。
      immediate: true,
      handler() {
        this.initSocket();
      },
    },
  },
  mounted() {
    this.initSocket()
    window.addEventListener('resize', this.onTerminalResize);
  },
  beforeDestroy() {
    this.socket.close()
    this.term&&this.term.dispose()
  },
  methods: {
   initTerm() {
      // this.initSocket();
      let term = new Terminal({
        rendererType: "canvas", //渲染类型
        rows: this.rows, //行数
        cols: this.cols, // 不指定行数,自动回车后光标从下一行开始
        convertEol: true, //启用时,光标将设置为下一行的开头
        // scrollback: 50, //终端中的回滚量
        disableStdin: false, //是否应禁用输入
        windowsMode: true, // 根据窗口换行
        // cursorStyle: "underline", //光标样式
        cursorBlink: true, //光标闪烁
        theme: {
          foreground: "#ECECEC", //字体
          background: "#000000", //背景色
          cursor: "help", //设置光标
          lineHeight: 20,
        },
      });
      this.term = term;
      const fitAddon = new FitAddon();
      this.term.loadAddon(fitAddon);
      this.fitAddon = fitAddon;
      let element = document.getElementById("xterm");
      term.open(element);
      // 自适应大小(使终端的尺寸和几何尺寸适合于终端容器的尺寸),初始化的时候宽高都是对的
      fitAddon.fit();
      term.focus();
      //监视命令行输入
      this.term.onData((data) => {
        let dataWrapper = data;
        if (dataWrapper === "\r") {
          dataWrapper = "\n";
        } else if (dataWrapper === "\u0003") {
          // 输入ctrl+c
          dataWrapper += "\n";
        }
        // 将输入的命令通知给后台,后台返回数据。
        this.socket.send(JSON.stringify({ type: "input", data: dataWrapper }));
      });
      window.addEventListener("resize", this.onTerminalResize);
    },
    onTerminalResize() {
      const terminalContainer = document.getElementById("xterm");
      const width = terminalContainer.parentElement.clientWidth;
      const height = terminalContainer.parentElement.clientHeight;
      const { term } = this;
      // 计算cols,rows
      const cols =
        (width - term._core.viewport.scrollBarWidth - 15) /
        term._core._renderService._renderer.dimensions.actualCellWidth;
      const rows =
        height /
          term._core._renderService._renderer.dimensions.actualCellHeight -
        1;
      this.term.resize(
        parseInt(cols.toString(), 10),
        parseInt(rows.toString(), 10)
      );
    },
    initSocket() {
      if (this.socketURI == "") {
        return;
      }
      this.socket = new WebSocket(this.socketURI);
      this.socketOnClose();
      this.socketOnOpen();
      this.socketOnmessage();
      this.socketOnError();
    },
    socketOnOpen() {
      this.socket.onopen = () => {
        console.log("web链接成功");
        // 链接成功后
        this.initTerm();
        this.onTerminalResize();
      };
    },
    socketOnmessage() {
      this.socket.onmessage = (evt) => {
        try {
          if (typeof evt.data === "string") {
            const msg = evt.data;
            // 将返回的数据写入xterm,回显在webshell上
            this.term.write(msg);
            // 此处可以判断一下,如果是首次连接,需要将rows,cols传给服务器端
            // when server ready for connection,send resize to server
            this.socket.send(
              JSON.stringify({
                type: "resize",
                rows: this.term.rows,
                cols: this.term.cols,
              })
            );
          }
        } catch (e) {
          console.error(e);
          console.log("parse json error.", evt.data);
        }
      };
    },
    socketOnClose() {
      this.socket.onclose = () => {
        this.socket.close();
        console.log("关闭 socket");
        // if (this.socket) {
        //   this.socket.close();
        // }
        window.removeEventListener("resize", this.onTerminalResize);
      };
    },
    socketOnError() {
      this.socket.onerror = () => {
        console.log("socket 链接失败");
      };
    },
}
</script>
 类似资料: