xterm.js + vue + websocket实现终端功能(xterm 3.x+xterm 4.x)

之前使用的xterm 3.x的粘贴功能不能用了,于是又改用了4.x的,我把所有的代码都放在这里吧,大家有问题也可以积极来探讨哦~

xterm github官网

一、使用流程

1.引入xterm.js

2.创建xterm实例并挂载到dom上

3.xterm全屏调整

4.xterm与websocket结合发送数据并显示在屏幕上


二、需要注意

1.关于输入与粘贴

xterm4.x应该是在2019年3月份就开始更新了,但现在网上用的大多数的版本还都是3.x,我之前用的是3.12,输入方法和粘贴方法分别用的是

term.on(‘key’,function()}
term.on(‘paste’, fuction()}

而xterm4.x版本后API取消了on事件,而直接使用on+事件名,格式也有所调整

term.onData(function(key) {
let order = {
Data: key,
Op: “stdin”
};
_this.onSend(order);
});

这里坑也挺大的,一开始我没注意看文档,只看了是onData方法,认为只要使用term.onData = function(){}赋值就可以,但是会报错

xterm.js :Cannot set property onData of #<e> which has only a getter”

然后后来查官网和资料才发现(这里要吐槽资料真是少的可怜啊),是要给onData方法传一个方法做为参数去执行,而不是给它赋值。

2.关于全屏

然后就是关于全屏,因为之前受资料与知识范围限制发现4.x没有fullscreen方法所以才使用的3.x(在这里我要吐槽一下这个xterm.js的官网,真真是辣鸡的很,什么都不写清楚,就实例一下就完事了,好多参数和方法api里也不给个例子,还得自己到处去找,真的很辣鸡!!!),一开始以为4.0中不需要设置fit及fullscreen,引入css后直接设置行数和列数就能实现背景铺满全屏。

但遇到一个问题是,xterm默认代码不会占满一整行,而是会直接换行,所以这里我们需要使用到官网首页给到的插件。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200610145046950.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zODMxODI0NA==,size_16,color_FFFFFF,t_70

    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实现仿终端功能时,不需要对输入字符进行判断,也不需要在输入事件中把输入的字符打出来。因为在输入事件中执行的web socket连接中,每输入一个字符都会自动传到后端,而后端会根据你输入的回车符来判断是否要为你换行及返回何种数据。(来,重要的话跟我念三遍~)

我们不必关心用户输入与想做的操作,只需要向后台传递参数就好。
我们不必关心用户输入与想做的操作,只需要向后台传递参数就好。
我们不必关心用户输入与想做的操作,只需要向后台传递参数就好。

4.实现web terminal代码

(1).xterm 4.4.0(最新)

(下面就是整个文件的方法啦,此实例不能直接复制使用哦,因为websocket是封装好的,大家看一下使用方法就好~)

<template>
  <div
    style="height: 100%;
    background: #002833;"
  >
    <div id="terminal" ref="terminal"></div> //terminal容器
  </div>
</template>

<script>
// 引入xterm,请注意这里和3.x版本的引入路径不一样
import {
    Terminal } from "xterm";
import "xterm/css/xterm.css";
import "xterm/lib/xterm.js";

export default {
   
  name: "Shell",
  data() {
   
    return {
   
      shellWs: "",
      term: "", // 保存terminal实例
      rows: 40,
      cols: 100
    };
  },

  created() {
   
    this.wsShell();
  },

  mounted() {
   
    let _this = this;
    // 获取容器宽高/字号大小,定义行数和列数
    this.rows = document.querySelector(".indexContainer").offsetHeight / 16 - 6;
    this.cols = document.querySelector(".indexContainer").offsetWidth / 14;

    let term = new Terminal({
   
      rendererType: "canvas", //渲染类型
      rows: parseInt(_this.rows), //行数
      cols: parseInt(_this.cols), // 不指定行数,自动回车后光标从下一行开始
      convertEol: true, //启用时,光标将设置为下一行的开头
      //   scrollback: 50, //终端中的回滚量
      disableStdin: false, //是否应禁用输入。
      cursorStyle: "underline", //光标样式
      cursorBlink: true, //光标闪烁
      theme: {
   
        foreground: "#7e9192", //字体
        background: "#002833", //背景色
        cursor: "help", //设置光标
        lineHeight: 16
      }
    });

    // 创建terminal实例
    term.open(this.$refs["terminal"]);

    // 换行并输入起始符“$”
    term.prompt = () => {
   
      term.write("\r\n$ ");
    };
    term.prompt();

    // // canvas背景全屏
    var fitAddon = new FitAddon();
    term.loadAddon(fitAddon);
    fitAddon.fit();

    window.addEventListener("resize", resizeScreen);

    // 内容全屏显示
    function resizeScreen() {
   
      // 不传size

      try {
   
        fitAddon.fit();

        // 窗口大小改变时触发xterm的resize方法,向后端发送行列数,格式由后端决定
        // 这里不使用size默认参数,因为改变窗口大小只会改变size中的列数而不能改变行数,所以这里不使用size.clos,而直接使用获取我们根据窗口大小计算出来的行列数
        term.onResize(() => {
   
          _this.onSend({
    Op: "resize", Cols: term.cols, Rows: term.rows });
        });
      } catch (e) {
   
        console.log("e", e.message);
      }
    }

    function runFakeTerminal(_this) {
   
      if (term._initialized) {
   
        return;
      }
      // 初始化
      term._initialized = true;

      term.writeln("Welcome to use Superman. ");
      term.writeln(
        `This is Web Terminal of pod\x1B[1;3;31m ${
     
          _this.urlParam.podName
        }\x1B[0m in namespace\x1B[1;3;31m ${
     _this.urlParam.namespace}\x1B[0m`
      );

      term.prompt();

      // / **
      //     *添加事件监听器,用于按下键时的事件。事件值包含
      //     *将在data事件以及DOM事件中发送的字符串
      //     *触发了它。
      //     * @返回一个IDisposable停止监听。
      //  * /
      //   / ** 更新:xterm 4.x(新增)
      //  *为数据事件触发时添加事件侦听器。发生这种情况
      //  *用户输入或粘贴到终端时的示例。事件值
      //  *是`string`结果的结果,在典型的设置中,应该通过
      //  *到支持pty。
      //  * @返回一个IDisposable停止监听。
      //  * /
      // 支持输入与粘贴方法
      term.onData(function(key) {
   
        let order = {
   
          Data: key,
          Op: "stdin"
        };
        _this.onSend(order);
        // 为解决窗体resize方法才会向后端发送列数和行数,所以页面加载时也要触发此方法
        _this.onSend({
   
          Op: "resize",
          Cols: parseInt(term.cols),
          Rows: parseInt(term.rows)
        });
      });

      _this.term = term;
    }
    runFakeTerminal(_this);

  },

  methods: {
   
  
    /**
     * **wsShell 创建页面级别的websocket,加载页面数据
     * ws 接口:/xxx/xxx/xxx
     * 参数:无
     * ws参数:
     * @deployId   任务id
     * @tagString  当前节点
     * 返回:无
     * **/
    wsShell() {
   
      const _this = this;
      let tag = this.urlParam.Tag;
      let name= this.urlParam.name;
      let pod= this.urlParam.pod;

      let query = `?tag=${
     tag}&name=${
     name}&pod=${
     pod}`;
      let url = `xxxx/xxxx${
     query}`// websocket连接接口

      this.shellWs = this.base.WS({
   
        url,
        isInit: true,
        openFn() {
   
          //   _this.term.resize({ rows: _this.rows, cols: 100 }); //终端窗口重新设置大小 并触发term.on("resize")
        },
        messageFn(e) {
   
          console.log("message", e);
          
评论 111
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值