xterm.js 使用及问题【新】

xterm.js 使用及问题【新】

版本

xterm:4.15.0

xterm-addon-fit:0.5.0

问题

  1. 如果初始化的时候就使用fit,那么屏幕缩小小于初始的宽度。

issues3564

a

在初始化的时候不能使用fit

  mounted() {
    this.term = this.initTerm()
    this.onTerminalResize()
    this.onTerminalKeyPress()
  },
 methods:{
	initTerm() {
    const term = new Terminal(this.option)
    this.fitAddon = new FitAddon()
    term.loadAddon(this.fitAddon)
    term.open(this.$refs.terminal)
    term.write(this.initText)
    // this.fitAddon.fit() // 初始化的时候不要使用fit

    return term
	},
}

使用fit的时机

  mounted() {
    this.term = this.initTerm()
    this.onTerminalResize()
    this.onTerminalKeyPress()
    
    setTimeout(() => {
      this.fitAddon.fit()
    }, 60) // 而且不能是0 ,xterm 生成时间在2ms左右
  },

⚠️不能使用 nextTick 替代setTimeout

⚠️setTimeout的时间⏰,xterm 生成时间在2ms左右,如果设置成5,初始进入好使,刷新浏览器的时候,就又不好使了。经测试,有可能是刷新浏览器时,xterm销毁并重建,设置成11时,是好使的。结论:setTimeout的时间要设置的大一点

代码

<template>
  <div class="terminal-cantainer">
    <div ref="terminal" style="width: 100%; height: 100%; display: block"></div>
  </div>
</template>

<script>
import { Terminal } from 'xterm'
import { FitAddon } from 'xterm-addon-fit'
import 'xterm/css/xterm.css'
import { debounce } from 'lodash'

const packStdin = data =>
  JSON.stringify({
    Op: 'stdin',
    Data: data
  })

const packResize = (col, row) =>
  JSON.stringify({
    Op: 'resize',
    Cols: col,
    Rows: row
  })
export default {
  name: 'Terminal',
  data() {
    return {
      initText: '连接中...',
      first: true,
      term: null,
      fitAddon: null,
      ws: null,
      socketUrl:'ws://localhost:8081',
      option: {
        lineHeight: 1.2,
        cursorBlink: true,
        cursorStyle: 'underline',
        fontSize: 12,
        fontFamily: "Monaco, Menlo, Consolas, 'Courier New', monospace",
        theme: {
          background: '#181d28'
        },
        cols: 10 // 初始化的时候不要设置fit,设置col为较小值(最小为可展示initText初始文字即可)方便屏幕缩放
      }
    }
  },
  computed: {
    isWsOpen() {
      return this.ws && this.ws.readyState === 1
    }
  },
  mounted() {
    this.term = this.initTerm()
    this.initSocket()

    this.onTerminalResize()
    this.onTerminalKeyPress()

    setTimeout(() => {
      this.fitAddon.fit()
    }, 60) // ⚠️
  },
  beforeDestroy() {
    this.removeResizeListener()
    this.term && this.term.dispose()
  },
  methods: {
    initTerm() {
      const term = new Terminal(this.option)
      this.fitAddon = new FitAddon()
      term.loadAddon(this.fitAddon)
      term.open(this.$refs.terminal)
      term.write(this.initText)
      // this.fitAddon.fit() // 初始化的时候不要使用fit
      return term
    },
    onTerminalKeyPress() {
      this.term.onData(data => {
        this.isWsOpen && this.ws.send(packStdin(data))
      })
    },

    // resize 相关
    resizeRemoteTerminal() {
      const { cols, rows } = this.term
      console.warn('cols, rows', cols, rows)
      // 调整后端终端大小 使后端与前端终端大小一致
      this.isWsOpen && this.ws.send(packResize(cols, rows))
    },
    onResize: debounce(function () {
      this.fitAddon.fit()
    }, 500),
    onTerminalResize() {
      window.addEventListener('resize', this.onResize)
      this.term.onResize(this.resizeRemoteTerminal)
    },
    removeResizeListener() {
      window.removeEventListener('resize', this.onResize)
    },

    // socket
    initSocket() {
      this.ws = new WebSocket(this.socketUrl)
      this.openSocket()
      this.closeSocket()
      this.errorSocket()
      this.messageSocket()
    },
    // 打开连接
    openSocket() {
      this.ws.onopen = () => {
        console.log('打开连接')
      }
    },
    // 关闭连接
    closeSocket() {
      this.ws.onclose = () => {
        console.log('关闭连接')
      }
    },
    // 连接错误
    errorSocket() {
      this.ws.onerror = () => {
        this.$message.error('websoket连接失败,请刷新!')
      }
    },
    // 接收消息
    messageSocket() {
      this.ws.onmessage = res => {
        const data = JSON.parse(res.data)
        const term = this.term
        console.warn('data', data)
        // 第一次连接成功将 initText 清空
        if (this.first) {
          this.first = false
          term.reset()
          term.element && term.focus()
          this.resizeRemoteTerminal()
        }
        term.write(data.Data)
      }
    }
  }
}
//
</script>
<style lang="scss">
.terminal-cantainer {
  height: 100%;
  border-radius: 4px;
  background: rgb(24, 29, 40);
  padding: 12px;
  color: rgb(255, 255, 255);
  .xterm-scroll-area::-webkit-scrollbar-thumb {
    background-color: #b7c4d1; /* 滚动条的背景颜色 */
  }
}
</style>

问题

Vue 监听不到ws.readyState变化

https://segmentfault.com/q/1010000023263992

解决方法: 在onopen、onclose、onerror、onmessage 手动修改状态。

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值