【个人笔记】vue+xterm.js+novnc实现终端交互和远程桌面

介绍一个 VNC连接工具:iis7服务器管理工具
IIs7服务器管理工具可以批量连接并管理VNC服务器
作为服务器集成管理器,它最优秀的功能就是批量管理windows与linux系统服务器、vps。能极大的提高站长及服务器运维人员工作效率。同时iis7服务器管理工具还是vnc客户端,服务器真正实现了一站式管理,可谓是非常方便。
下载地址:http://fwqglgj.iis7.net/cp/vnc/?tscc在这里插入图片描述

最近公司有一个项目需要实现页面终端交互,另一个是连接VNC,终端一开始是使用webshell实现的,如果直接用webshell的话,因为是前后端分离就避免不了要用iframe去嵌套,VNC同样,所以就把webshell更换成xterm.js,VNC更换成novnc,两个插件把iframe去掉了,此处做一个记录
由于xterm.js官方还是比较坑的,没什么比较完整的实例,在网上搜索的资料很多没有表明版本号导致浪费了很多的时间,此处先说使用版本xterm.js-------3.12.0 @novnc/novnc------1.1.0
#@novnc/novnc使用还是比较简单的,网上搜索基本问题不大
#html
<div id='shell'>
   <div id="screen"></div>
</div>
#先引入
import RFB from '@novnc/novnc/core/rfb'
#data参数
rfb:null,
url: 'ws://'......', //链接的url
IsClean: false, //是否已断开并不可重新连接
connectNum:0, //重连次数,
#methods
// vnc连接断开的回调函数
disconnectedFromServer (msg) {
    if(msg.detail.clean){
        // 根据 断开信息的msg.detail.clean 来判断是否可以重新连接
        this.contentVnc()
    } else {
        //这里做不可重新连接的一些操作
    }
},
// 连接成功的回调函数
connectedToServer() {
    console.log('success')
},

//连接vnc的函数

connectVnc () {
    const PASSWORD = this.pwd;
    let rfb = new RFB(document.getElementById('screen'), this.url, {
    // 向vnc 传递的一些参数,比如说虚拟机的开机密码等
        credentials: {password: PASSWORD}
    });
    rfb.addEventListener('connect', this.connectedToServer);
    rfb.addEventListener('disconnect', this.disconnectedFromServer);
    // rfb.scaleViewport = true;  //scaleViewport指示是否应在本地扩展远程会话以使其适合其容器。禁用时,如果远程会话小于其容器,则它将居中,或者根据clipViewport它是否更大来处理。默认情况下禁用。
    // rfb.resizeSession = true; //是一个boolean指示是否每当容器改变尺寸应被发送到调整远程会话的请求。默认情况下禁用
    this.rfb = rfb;
    
}
#再mounted中引用
this.connectVnc()
#自适应宽高
function changeMobsfIframe(){
    const mobsf = document.getElementById('screen');
     const deviceWidth = document.body.clientWidth;
     const deviceHeight = document.body.clientHeight;
     mobsf.style.width = 100 + '%'; //数字是页面布局宽度差值
     mobsf.style.height = (Number(deviceHeight)-109) + 'px'; //数字是页面布局高度差
 }

 changeMobsfIframe()

 window.onresize = function(){
     changeMobsfIframe()
 }
使用xterm.js特别小心版本,因为3.和4.版本区别还是比较大的,3.里面像fit、attach已经被拿出来了,xterm.on也更换了用法,具体的更新参考以下:https://github.com/xtermjs/xterm.js/releases/tag/4.0.0

我的配置也感谢下面这位小姐姐:
https://blog.csdn.net/weixin_38318244/article/details/103908129

#html
<div
  style="height: 100%;
  background: #002833;"
>
  <div id="terminal" ref="terminal"></div>
</div>
#需要引入
import { Terminal } from "xterm";
import "xterm/dist/xterm.css";
import * as fit from "xterm/lib/addons/fit/fit";
import * as fullscreen from "xterm/lib/addons/fullscreen/fullscreen";            //全屏
import * as attach from "xterm/lib/addons/attach/attach";
Terminal.applyAddon(fit);
Terminal.applyAddon(attach);
Terminal.applyAddon(fullscreen); // Apply the `fullscreen` addon
#data参数
order: "",
urlParam: {
  fullTag: "",
  namespace: "",
  podName: ""
},
shellWs: "",         //ws实例
term: "", // 保存terminal实例
showOrder: "", // 保存服务端返回的命令
rows: 40,
cols: 100,
#mounted初始化配置
let _this = this;
    this.rows = document.body.offsetHeight / 16 - 9;
    this.cols = document.body.offsetWidth / 14;

    //this.cols = 400

    let term = new Terminal({
      rendererType: "canvas", //渲染类型
      rows: parseInt(_this.rows), //行数
      cols: parseInt(_this.cols), // 不指定行数,自动回车后光标从下一行开始
      convertEol: true, //启用时,光标将设置为下一行的开头
      scrollback: 800,  //终端中的回滚量
      disableStdin: false, //是否应禁用输入。
      cursorStyle: "underline", //光标样式
      cursorBlink: true, //光标闪烁
      theme: {
        foreground: "#ffffff", //字体
        background: "#002833", //背景色
        cursor: "help", //设置光标
        lineHeight: 16
      }
    });
    // 换行并输入起始符“$”
    term.prompt = () => {
      term.write("\r\n$ ");
    };
    // Load WebLinksAddon on terminal, this is all that's needed to get web links
    // working in the terminal.
    // term.loadAddon(new WebLinksAddon());

    term.open(this.$refs["terminal"]);
    term.toggleFullScreen(); //全屏

    window.onresize = function() {
      term.fit();
      term.toggleFullScreen(); //全屏
      term.prompt();
    }
    function runFakeTerminal(_this) {
      if (term._initialized) {
        return;
      }

      term._initialized = true;

      term.prompt = () => {
        term.write("\r\n ");
      };

      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();

      //   console.log("term", term);

      // 监控键盘输入事件
      // / **
      //     *添加事件监听器,用于按下键时的事件。事件值包含
      //     *将在data事件以及DOM事件中发送的字符串
      //     *触发了它。
      //     * @返回一个IDisposable停止监听。
      //  * /

      term.on("key", function(key) {
        let order = {
          data: key,
          status: 0
        };            //重点是这里,主要还是要看清楚你的后台接收的数据是什么样的,不一定是{data:'',status:''},这个坑踩得我很惨,要看后台的接收数据!!!
        _this.onSend(order);
      });

      term.on("paste", function(data) {
        _this.order = data;
        term.write(data);
      });

      term.on("resize", size => {
        let order = {
          Rows: parseInt(size.rows),
          Cols: parseInt(size.cols),
          Op: "resize"
        };

        _this.onSend(order);
      });

      _this.term = term;
    }
    runFakeTerminal(_this);
#methods
/**
     * **wsShell 创建页面级别的websocket,加载页面数据
     * ws 接口:/v1/task/deploy/detail/container
     * 参数:无
     * ws参数:
     * @deployId   任务id
     * @tagString  当前节点
     * 返回:无
     * **/
    wsShell() {            //记得在created中调用
        const _this = this;
        this.shellWs = new WebSocket('ws://.....')                     //建立websocket,因为xterm.js是用websocket做交互的     
        this.shellWs.onopen = function(){
            console.log('open')
        },
        this.shellWs.onmessage = function(e){
            let data = JSON.parse(e.data)
            if (data.message == "\n" || data.message == "\r\nexit\r\n") {
              _this.$message.error("连接已关闭");
            }
            _this.term.write(data.message);
            _this.showOrder = data.message;
            _this.order = "";
        }
        this.shellWs.onclose= function(){
            _this.$message.error({
                message: "ws 请求失败,请刷新重试~",
                duration: 5000
            });
        }
    },

    onSend(data) {
        const _this = this
    //   data = this.base.isObject(data) ? JSON.stringify(data) : data;          //这两个具体作用在本配置没什么作用了,具体看小姐姐的用处
    //   data = this.base.isArray(data) ? data.toString() : data;
        data = JSON.stringify(data)
        data = data.replace(/\\\\/, "\\");
        _this.shellWs.send(data);
    },

    //删除左右两端的空格
    trim(str) {
      return str.replace(/(^\s*)|(\s*$)/g, "");
    }
根据引用[1]中提供的API文档,noVNC库本身并没有提供直接的复制粘贴功能。然而,你可以通过在noVNC中使用Clipboard.js库来实现复制粘贴功能。下面是一个示例代码,演示了如何在Vue中使用noVNC和Clipboard.js实现复制粘贴功能: 首先,确保你已经在项目中安装了noVNC和Clipboard.js库。 ```vue <template> <div> <div ref="vncContainer"></div> <button @click="copyToClipboard">复制</button> <button @click="pasteFromClipboard">粘贴</button> </div> </template> <script> import noVNC from 'novnc-core'; import ClipboardJS from 'clipboard'; export default { mounted() { // 创建noVNC实例 const vnc = noVNC.createClient(); vnc.mount(this.$refs.vncContainer); // 连接到VNC服务器 vnc.connect('ws://your-vnc-server-url'); // 初始化Clipboard.js const clipboard = new ClipboardJS('.copy-btn'); // 监听复制成功事件 clipboard.on('success', () => { console.log('复制成功'); }); // 监听粘贴成功事件 clipboard.on('paste', () => { console.log('粘贴成功'); }); }, methods: { copyToClipboard() { // 将文本复制到剪贴板 const text = '要复制的文本'; const input = document.createElement('input'); input.value = text; document.body.appendChild(input); input.select(); document.execCommand('copy'); document.body.removeChild(input); }, pasteFromClipboard() { // 从剪贴板中获取文本 const text = navigator.clipboard.readText(); text.then((content) => { console.log('从剪贴板中获取到的文本:', content); }); }, }, }; </script> ``` 上述代码中,我们首先在Vue组件中创建了一个noVNC实例,并将其挂载到一个容器元素上。然后,我们初始化了Clipboard.js,并在复制和粘贴按钮上添加了相应的点击事件处理函数。在复制按钮的点击事件处理函数中,我们使用`document.execCommand('copy')`将指定的文本复制到剪贴板。在粘贴按钮的点击事件处理函数中,我们使用`navigator.clipboard.readText()`从剪贴板中获取文本内容。 请注意,上述代码只是一个示例,你需要根据你的具体需求进行适当的修改和调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值