vue3 终端实现 (vue3+xterm+websocket)

news2024/9/23 1:35:41

 

目录

一、xterm介绍

二、效果展示

三、vue文件实现代码


一、xterm介绍

xterm是一个使用 TypeScript 编写的前端终端组件,可以直接在浏览器中实现一个命令行终端应用,通常与websocket一起使用。

二、效果展示

三、vue文件实现代码

<template>
  <div class="bg-main">
    <div
      ref="terminal"
      v-loading="loading"
      class="terminal"
      element-loading-text="拼命连接中"
    ></div>
  </div>
</template>
<script setup>
  import { ref, onMounted, onBeforeUnmount } from 'vue'
  import { debounce } from 'lodash'
  import { Terminal } from 'xterm'
  import { FitAddon } from 'xterm-addon-fit'
  import 'xterm/css/xterm.css'

  const terminal = ref(null)
  const fitAddon = new FitAddon()

  let first = ref(true)
  let loading = ref(true)
  let terminalSocket = ref(null)
  let term = ref(null)

  // 初始化WS
  const initWS = () => {
    if (!terminalSocket.value) {
      createWS()
    }
    if (terminalSocket.value && terminalSocket.value.readyState > 1) {
      terminalSocket.value.close()
      createWS()
    }
  }

  // 创建WS
  const createWS = () => {
    // const url = `/access/Api/ws/ssh/b172df81-2485-453d-a6ff-120c03821536?userName=test&passwd=1`
    terminalSocket.value = new WebSocket(
      `wss://XXXX`
    )
    terminalSocket.value.onopen = runRealTerminal //WebSocket 连接已建立
    terminalSocket.value.onmessage = onWSReceive //收到服务器消息
    terminalSocket.value.onclose = closeRealTerminal //WebSocket 连接已关闭
    terminalSocket.value.onerror = errorRealTerminal //WebSocket 连接出错
  }

  //WebSocket 连接已建立
  const runRealTerminal = () => {
    loading.value = false
  }
  //WebSocket收到服务器消息
  const onWSReceive = (message) => {
    // 首次接收消息,发送给后端,进行同步适配尺寸
    if (first.value === true) {
      first.value = false
      resizeRemoteTerminal()
    }
    const data = message.data
    // base64解密
    const reader = new FileReader()
    reader.onload = function (e) {
      const base64Content = e.target.result
      console.log(base64Content, 1)
      term.value.write(base64Content)
    }
    reader.readAsText(data) // 以text文本显示readAsText
    term.value.element && term.value.focus()
  }
  //WebSocket 连接出错
  const errorRealTerminal = (ex) => {
    let message = ex.message
    if (!message) message = 'disconnected'
    term.value.write(`\x1b[31m${message}\x1b[m\r\n`)
    console.log('err')
  }
  //WebSocket 连接已关闭
  const closeRealTerminal = () => {
    console.log('close')
  }

  // 初始化Terminal
  const initTerm = () => {
    term.value = new Terminal({
      // lineHeight: 1.2,
      fontSize: 14,
      fontFamily: "Monaco, Menlo, Consolas, 'Courier New', monospace",
      theme: {
        background: '#181d28',
      },
      // 光标闪烁
      cursorBlink: true,
      cursorStyle: 'underline',
      // scrollback: 100,
      // tabStopWidth: 4,
    })
    term.value.open(terminal.value) //挂载dom窗口
    term.value.loadAddon(fitAddon) //自适应尺寸
    // 不能初始化的时候fit,需要等terminal准备就绪,可以设置延时操作
    setTimeout(() => {
      fitAddon.fit()
    }, 5)
    termData() //Terminal 事件挂载
  }

  // 终端输入触发事件
  const termData = () => {
    // 输入与粘贴的情况,onData不能重复绑定,不然会发送多次
    term.value.onData((data) => {
      console.log(data, '传入服务器')
      if (isWsOpen()) {
        terminalSocket.value.send(
          JSON.stringify({
            type: 'terminal',
            data: {
              base64: btoa(data),
            },
          })
        )
      }
    })
    // 终端尺寸变化触发
    term.value.onResize(() => {
      resizeRemoteTerminal()
    })
  }

  //尺寸同步 发送给后端,调整后端终端大小,和前端保持一致,不然前端只是范围变大了,命令还是会换行
  const resizeRemoteTerminal = () => {
    const { cols, rows } = term.value
    if (isWsOpen()) {
      terminalSocket.value.send(
        JSON.stringify({
          type: 'resize',
          data: {
            rows: rows,
            cols: cols,
          },
        })
      )
    }
  }

  // 是否连接中0 1 2 3 状态
  const isWsOpen = () => {
    const readyState = terminalSocket.value && terminalSocket.value.readyState
    return readyState === 1
  }

  // 适应浏览器尺寸变化
  const fitTerm = () => {
    fitAddon.fit()
  }
  const onResize = debounce(() => fitTerm(), 500)
  const onTerminalResize = () => {
    window.addEventListener('resize', onResize)
  }
  const removeResizeListener = () => {
    window.removeEventListener('resize', onResize)
  }

  onMounted(() => {
    initWS()
    initTerm()
    onTerminalResize()
  })

  onBeforeUnmount(() => {
    removeResizeListener()
    terminalSocket.value && terminalSocket.value.close()
  })
</script>
<style lang="scss" scoped>
  .terminal {
    width: 100%;
    height: calc(100% - 62px);
  }
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1244731.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络安全如何自学?

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高&#xff1b; 二、则是发展相对成熟…

操作系统发展过程--单道批处理系统、多道批处理系统、分时系统、实时系统

一、单道批处理系统 计算机早期&#xff0c;为了能提高利用率&#xff0c;需要尽量保持系统的连续运行&#xff0c;即在处理完一个作业之后&#xff0c;紧接着处理下一个作业&#xff0c;以减少机器的空闲等待时间 1.单道批处理系统的处理过程 为了实现对作业的连续处理&…

Ubuntu开机显示No bootable devices found

Ubuntu开机报错&#xff0c;显示显示No bootable devices found&#xff0c;如下图所示&#xff1a; 解决方案如下&#xff1a; 1. F2进入BIOS (1) 重启开启&#xff0c;按F2进入BIOS系统。 (2) 进入Boot Sequence&#xff0c;目前系统选择了UEFI&#xff0c;而Legacy选项为…

学习.NET验证模块FluentValidation的基本用法(续1:其它常见用法)

FluentValidation模块支持链式验证方法调用&#xff0c;也就是说&#xff0c;除了 RuleFor(r > r.UserName).NotEmpty()调用方式之外&#xff0c;还可以将对单个属性的多种验证函数以链式调用方式串接起来&#xff0c;比如UserName属性不能为空&#xff0c;长度在5~10之间&a…

CTF-PWN-QEMU-前置知识

文章目录 QEMU 内存管理(QEMU 如何管理某个特定 VM 的内存)MemoryRegion gpa->hpaFlatView&#xff1a;表示MR 树对应的地址空间FlatRange&#xff1a;存储不同MR对应的地址信息AddressSpace&#xff1a;不同类型的 MemoryRegion树RAMBlock总体简化图 QEMU 设备模拟 &#x…

设计模式之建造者(Builder)模式

目录 1、什么是建造者Builder模式&#xff1f; 2、建造者Builder模式的利与弊 3、建造者Builder模式的应用场景 4、建造者模式中的指导者&#xff08;Director&#xff09;有什么作用&#xff1f; 5、建造者Builder模式与其他模式的关系 小结 1、什么是建造者Builder模式…

某60区块链安全之未初始化的存储指针实战一学习记录

区块链安全 文章目录 区块链安全未初始化的存储指针实战一实验目的实验环境实验工具实验原理实验过程 未初始化的存储指针实战一 实验目的 学会使用python3的web3模块 学会分析以太坊智能合约未初始化的存储指针漏洞 找到合约漏洞进行分析并形成利用 实验环境 Ubuntu18.04操…

飞书智能伙伴之 AI 数智参谋:先进团队,北极星指标也要遥遥领先

11 月 22 日&#xff0c;飞书在 2023 秋季飞书未来无限大会上正式发布了飞书智能伙伴。作为首批生态伙伴&#xff0c;基于 Kyligence 智能一站式指标平台实现的 AI 数智参谋也正式亮相。这是继 11 月 21 日 Kyligence 产品发布会后&#xff0c;Kyligence 在数据驱动决策智能领域…

python之pyqt专栏1-环境搭建

#python pyqt# python&#xff1a;3.11.6 pycharm&#xff1a;PyCharm Community Edition 2023.2.5 pyqt6 python安装 官网下载&#xff1a;Python Releases for Windows | Python.org pycharm社区版安装 官网地址&#xff1a;Download PyCharm: Python IDE for Professional…

CUDA与GPU编程

文章目录 CUDA与GPU编程1. 并行处理与GPU体系架构1.1 并行处理简介1.1.1 串行处理与并行处理的区别1.1.2 并行处理的概念1.1.3 常见的并行处理 1.2 GPU并行处理1.2.1 GPU与CPU并行处理的异同1.2.2 CPU的优化方式1.2.3 GPU的特点 1.3 环境搭建 CUDA与GPU编程 1. 并行处理与GPU体…

思维模型 潘多拉效应

本系列文章 主要是 分享 思维模型 &#xff0c;涉及各个领域&#xff0c;重在提升认知。越是禁止&#xff0c;越是好奇。 1 潘多拉效应的应用 1.1 潘多拉效应在管理中的应用 通用电气公司曾经推出了一项名为“六西格玛”的管理方法&#xff0c;该方法旨在通过优化业务流程和提…

土地利用数据技术服务

一、背景介绍 土地是人类赖以生存与发展的重要资源和物质保障&#xff0c;在“人口&#xff0d;资源&#xff0d;环境&#xff0d;发展&#xff08;PRED&#xff09;”复合系统 中&#xff0c;土地资源处于基础地位。随着现代社会人口的不断增长以及工业化、城市化进程的加速&a…

所有权成果输出(宗地基本信息表、界址标示表、界址签章表、界址点成果表、宗地图、界址说明表、调查审核表)

一、软件界面&#xff1a; 二、软件功能&#xff1a;主要实现批量生成不动产权籍调查表、宗地基本信息表、界址标示表、界址签章表、界址点成果表、宗地图、界址说明表、调查审核表。(本次宗地包含内外环宗地) 三、所有权成果要求(宗地基本信息表、界址标示表、界址签章表…

创作4周年

&#x1f64c;秋名山码民的主页 &#x1f602;oi退役选手&#xff0c;Java、大数据、单片机、IoT均有所涉猎&#xff0c;热爱技术&#xff0c;技术无罪 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; 获取源码&#xff0c;添加WX 目录 前言机…

工业一体全国产方案,米尔T113核心板

入门级HMI屏作为嵌入式系统中重要组成部分&#xff0c;大部分都是串口屏&#xff1b;其功能简单、成本低等特点&#xff0c;使用历史悠久、应用广泛&#xff0c;而随着信息技术的快速发展&#xff0c;行业需求不断升级&#xff0c;工程师使用了大量串口屏后&#xff0c;发现串口…

操作系统 day13(RR、优先级调度)

RR&#xff08;时间片轮转&#xff09; 响应时间&#xff1a;系统中有10个进程正在并发执行&#xff0c;如果时间片为1秒&#xff0c;则一个进程被响应可能需要等待9秒。也就是说&#xff0c;如果用户在自己进程的时间片外通过键盘发出调试命令&#xff0c;可能需要等待9秒才能…

大厂面试官最爱问的20道Mysql面试题

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

thinkphp6生成PDF自动换行

composer安装 composer require tecnickcom/tcpdf 示例 use TCPDF;public function info($university,$performance,$grade,$major){//获取到当前域名$domain request()->domain();//实例化$pdf new TCPDF(P, mm, A4, true, UTF-8, false);// 设置文档信息$pdf->SetCr…

Redis高可用之主从复制及哨兵模式

一、Redis的主从复制 1.1 Redis主从复制定义 主从复制是redis实现高可用的基础&#xff0c;哨兵模式和集群都是在主从复制的基础之上实现高可用&#xff1b; 主从复制实现数据的多级备份&#xff0c;以及读写分离(主服务器负责写&#xff0c;从服务器只能读) 1.2 主从复制流…

多线程的实现方式

点击链接返回标题-> Java线程的学习-CSDN博客 第一种方式&#xff0c;继承Thread类 Thread类是java.lang包下的类&#xff0c;是多线程经常需要使用的类。 ①通过自定义子类去继承Thread类&#xff0c;并重写其中的run()方法。 class myThread extends Thread {//自定义子类…