一、安装
npm install --save xterm xterm-addon-fit xterm-addon-attach
xterm-addon-fit
xterm.js的插件,使终端的尺寸适合包含元素。
xterm-addon-attach
xterm.js的附加组件,用于附加到Web Socket
二、代码
<template>
<div class="box">
<div id="xterm" class="xterm-box"></div>
</div>
</template>
<script>
import { Terminal } from 'xterm'
import { FitAddon } from 'xterm-addon-fit'
import 'xterm/css/xterm.css'
import 'xterm/lib/xterm.js'
export default {
data() {
return {
term: null,
socket: '',
WebSocketUrl: 'ws:192.168.5.10:8080/webide/terminal/17317181717',
//WebSocketUrl: 'ws:192.168.5.10:8080/terminal/17317181717', //ws接口ws:192.168.5.10:8080/terminal/17317181717
// 心跳
lockReconnect: false, //是否真正建立连接
timeout: 60 * 1000, //60秒一次心跳
timeoutObj: null, //心跳心跳倒计时
serverTimeoutObj: null, //心跳倒计时
timeoutnum: null, //断开 重连倒计时
}
},
mounted() {
this.init(this.WebSocketUrl)
},
//跑路前清除定时器
beforeDestroy() {
this.close()
clearTimeout(this.timeoutObj)
clearTimeout(this.serverTimeoutObj)
clearTimeout(this.timeoutnum)
},
methods: {
// 心跳函数--------------
reconnect() {
//重新连接
var that = this
if (that.lockReconnect) {
return
}
that.lockReconnect = true
//没连接上会一直重连,设置延迟避免请求过多
that.timeoutnum && clearTimeout(that.timeoutnum)
that.timeoutnum = setTimeout(function () {
//新连接
that.init(that.WebSocketUrl)
that.lockReconnect = false
}, 2000)
},
reset() {
//重置心跳
var that = this
//清除时间
clearTimeout(that.timeoutObj)
clearTimeout(that.serverTimeoutObj)
//重启心跳
that.start()
},
start() {
//开启心跳
var self = this
self.timeoutObj && clearTimeout(self.timeoutObj)
self.serverTimeoutObj && clearTimeout(self.serverTimeoutObj)
self.timeoutObj = setTimeout(function () {
//这里发送一个心跳,后端收到后,返回一个心跳消息,
if (self.socket.readyState == 1) {
//如果连接正常,有事没事发ping,具体根据要求
//self.socket.send('ping')
} else {
//否则重连
self.reconnect()
}
self.serverTimeoutObj = setTimeout(function () {
//超时关闭
self.close()
}, self.timeout)
}, self.timeout)
},
//-----------------
initXterm() {
if (this.term) {
this.term.dispose()
}
let height = document.body.clientHeight
this.term = new Terminal({
rendererType: 'canvas', //渲染类型
rows: 35, //行数 18是字体高度,根据需要自己修改
convertEol: true, //启用时,光标将设置为下一行的开头
scrollback: 800, //终端中的回滚量
disableStdin: false, //是否应禁用输入
cursorStyle: 'underline', //光标样式
cursorBlink: true, //光标闪烁
tabStopWidth: 8, //制表宽度
screenKeys: true,
theme: {
foreground: 'yellow', //字体
background: '#060101', //背景色
cursor: 'help', //设置光标
},
})
this.term.writeln('Welcome to use Superman. ')
this.term.open(document.getElementById('xterm'))
const fitAddon = new FitAddon()
this.term.loadAddon(fitAddon)
fitAddon.fit() //全屏
//window.addEventListener('resize', this.resizeScreen)
// 支持输入与粘贴方法
let _this = this //一定要重新定义一个this,不然this指向会出问题
let code = ''
let codeArr = '' //存储输入集合
this.term.onData(function (key) {
//codeArr += key
//_this.term.write(key)
let order = { operate: 'command', command: key }
//这里key值是你输入的值,数据格式order一定要找后端要!!!!
//if (key.length > 1) _this.term.write(key) //粘贴
//console.log(key, JSON.stringify(key))
_this.socket.onsend(JSON.stringify(order))
})
},
init(url) {
// 实例化socket
this.socket = new WebSocket(url)
// 监听socket连接
this.socket.onopen = this.open
// 监听socket错误信息
this.socket.onerror = this.error
// 监听socket消息
this.socket.onmessage = this.getMessage
// 发送socket消息
this.socket.onsend = this.send
},
open: function () {
console.log('socket连接成功')
//this.term.write('Welcome to use')
this.initXterm()
//开启心跳
this.start()
},
error: function () {
console.log('连接错误')
//重连
this.reconnect()
},
close: function () {
this.socket.close()
console.log('socket已经关闭')
//重连
this.reconnect()
},
getMessage: function (msg) {
//msg是返回的数据
//msg = JSON.parse(msg.data)
//msg = msg.data
//console.log(msg)
//this.socket.send('ping') //有事没事ping一下,看看ws还活着没
//switch用于处理返回的数据,根据返回数据的格式去判断
// switch (msg['operation']) {
// case 'stdout':
// this.term.write(msg['data']) //这里write也许不是固定的,失败后找后端看一下该怎么往term里面write
// break
// default:
// console.log('Unexpected message type:', msg) //但是错误是固定的。。。。
// }
this.term.write(msg['data']) //这里write也许不是固定的,失败后找后端看一下该怎么往term里面write
//收到服务器信息,心跳重置
this.reset()
},
send: function (order) {
//console.log(order)
this.socket.send(order)
},
resizeScreen(size) {
console.log('size', size)
var fitAddon = new FitAddon()
term.loadAddon(fitAddon)
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)
}
},
},
}
</script>
</script>
<style lang="scss" scoped>
.box {
width: 100%;
height: 100%;
.xterm-box {
width: 100%;
height: 100%;
}
}
</style>