<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>前端终端,操作后端的docker容器</title>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/css/xterm.css">
</head>
<body class="bodyCss">
<div id="app">
<div id="terminal" ></div>
</div>
</body>
<script src="https://unpkg.com/[email protected]/lib/xterm.js"></script>
<script src="https://lib.baomitu.com/vue/2.6.14/vue.js"></script>
<script src="https://unpkg.com/[email protected]/lib/xterm-addon-fit.js"></script>
<script src="https://unpkg.com/[email protected]/lib/xterm-addon-attach.js"></script>
<script>
let wsTime = null
new Vue({
el: '#app',
data() {
return {
// 终端
term:{},
// websocket
ws:{}
}
},
created(){
// 初始化终端
this.initTerminal()
},
mounted() {
// 建立websocket连接
this.websocket()
},
beforeDestroy() {
this.ws.close()
this.term.dispose()
},
methods: {
// 初始化终端配置
initTerminal(){
this.term = new Terminal({
rendererType: "canvas", //渲染类型
// rows: 40, //行数,影响最小高度
// cols: 100, // 列数,影响最小宽度
convertEol: true, //启用时,光标将设置为下一行的开头
// scrollback: 50, //终端中的滚动条回滚量
disableStdin: false, //是否应禁用输入。
cursorStyle: "underline", //光标样式
cursorBlink: true, //光标闪烁
theme: {
foreground: '#F8F8F8',
background: '#2D2E2C',
cursor: "help", //设置光标
lineHeight: 16,
},
fontFamily: '"Cascadia Code", Menlo, monospace'
});
},
// 自定义终端默认展示内容
writeDefaultInfo(){
let defaultInfo = [
'┌\x1b[1m terminals \x1b[0m─────────────────────────────────────────────────────────────────┐ ',
'│ │ ',
'│ \x1b[1;34m 欢迎使用Web Docker SSH \x1b[0m │ ',
'│ │ ',
'└────────────────────────────────────────────────────────────────────────────┘ ',]
this.term.write(defaultInfo.join('\n\r'))
},
// 建立websocket连接
websocket() {
// WebSocket start
if ('WebSocket' in window) {
//需要修改ip和id
//例如:const url = `ws://192.168.111.222:2375/v1.41/containers/0eb8aafb4e6e/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1`
const url = `ws://你的ip/v1.41/containers/你的id/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1`
const ws = new WebSocket(url)
this.ws = ws
ws.onopen = (event) => {
console.log('已建立连接:',event)
// 输入换行符可让终端显示当前用户的工作路径
ws.send('\n')
// 窗口自适应插件
const fitAddon = new FitAddon.FitAddon();
// websocket自动收发消息插件
const attachAddon = new AttachAddon.AttachAddon(ws)
this.term.loadAddon(attachAddon)
this.term.loadAddon(fitAddon)
this.term.open(document.getElementById('terminal'));
// 聚焦闪烁光标
this.term.focus()
// 窗口尺寸变化时,终端尺寸自适应
window.onresize = () => {
fitAddon.fit()
}
// 自定义终端默认展示内容
this.writeDefaultInfo()
};
ws.onmessage = (event) => {
console.log('接收信息:',event)
};
ws.onerror = (event) => {
console.log('错误信息:', event)
if (wsTime) {
window.clearTimeout(wsTime)
wsTime = null
}
wsTime = window.setTimeout(() => {
this.websocket()
}, 3000)
};
ws.onclose = (event) => {
console.log('已关闭连接:', event)
// if (wsTime) {
// window.clearTimeout(wsTime)
// wsTime = null
// }
// wsTime = window.setTimeout(() => {
// this.websocket()
// }, 3000)
};
} else {
console.log('浏览器不支持 WebSocket..')
}
// WebSocket end
}
}
})
</script>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>前端终端,操作后端的docker容器</title>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/css/xterm.css">
</head>
<body class="bodyCss">
<div id="app">
<div id="terminal" ></div>
</div>
</body>
<script src="https://unpkg.com/[email protected]/lib/xterm.js"></script>
<script src="https://lib.baomitu.com/vue/2.6.14/vue.js"></script>
<script src="https://unpkg.com/[email protected]/lib/xterm-addon-fit.js"></script>
<script>
let wsTime = null
new Vue({
el: '#app',
data() {
return {
// 终端
term:{},
// websocket
ws:{},
// 用户输入
command:''
}
},
created(){
// 初始化终端
this.initTerminal()
},
mounted() {
// 建立websocket连接
this.websocket()
},
beforeDestroy() {
this.ws.close()
this.term.dispose()
},
methods: {
// 初始化终端配置
initTerminal(){
this.term = new Terminal({
rendererType: "canvas", //渲染类型
// rows: 40, //行数,影响最小高度
// cols: 100, // 列数,影响最小宽度
convertEol: true, //启用时,光标将设置为下一行的开头
// scrollback: 50, //终端中的滚动条回滚量
disableStdin: false, //是否应禁用输入。
cursorStyle: "underline", //光标样式
cursorBlink: true, //光标闪烁
theme: {
foreground: '#F8F8F8',
background: '#2D2E2C',
cursor: "help", //设置光标
lineHeight: 16,
},
fontFamily: '"Cascadia Code", Menlo, monospace'
});
},
// 自定义终端默认展示内容
writeDefaultInfo(){
let defaultInfo = [
'┌\x1b[1m terminals \x1b[0m─────────────────────────────────────────────────────────────────┐ ',
'│ │ ',
'│ \x1b[1;34m 欢迎使用Web Docker SSH \x1b[0m │ ',
'│ │ ',
'└────────────────────────────────────────────────────────────────────────────┘ ',]
// 测试颜色区间
// let arr = Array.from({length:100},(v,i)=>v = i)
// console.log(arr)
// arr.map((item,i) => {
// defaultInfo.push(`Hello from \x1B[1;3;${i}m ${i} \x1B[0m \u2764\ufe0f ${i}`)
// })
this.term.write(defaultInfo.join('\n\r'))
this.writeOfColor('我是加粗斜体红色的字呀','1;3;','31m')
// this.term.write('\n\r$ ')
},
//
writeOfColor(txt, fontCss = "", bgColor = ""){
// 在Linux脚本中以 \x1B[ 开始,中间前部分是样式+内容,以 \x1B[0m 结尾
// 示例 \x1B[1;3;31m 内容 \x1B[0m
// fontCss
// 0;-4;字体样式(0;正常 1;加粗 2;变细 3;斜体 4;下划线)
// bgColor
// 30m-37m字体颜色(30m:黑色 31m:红色 32m:绿色 33m:棕色字 34m:蓝色 35m:洋红色/紫色 36m:蓝绿色/浅蓝色 37m:白色)
// 40m-47m背景颜色(40m:黑色 41m:红色 42m:绿色 43m:棕色字 44m:蓝色 45m:洋红色/紫色 46m:蓝绿色/浅蓝色 47m:白色)
this.term.write(`\x1B[${fontCss}${bgColor}${txt}\x1B[0m`)
},
// 监听输入
userWrite(){
this.term.onData(e => {
switch (e) {
case '\u0003': // Ctrl+C
this.term.write('^C ');
this.term.write('\r\n$ ')
break;
case '\r': // Enter
this.ws.send(this.command)
this.ws.send('\n')
this.command = ''
// this.term.write('\r\n$ ')
break;
case '\u007F': // Backspace (DEL)
// Do not delete the prompt
if (this.term._core.buffer.x > 2) {
this.term.write('\b \b');
if (this.command.length > 0) {
this.command = this.command.substr(0, this.command.length - 1);
}
}
break;
default: // Print all other characters for demo
if (e >= String.fromCharCode(0x20) && e <= String.fromCharCode(0x7E) || e >= '\u00a0') {
this.command += e;
this.writeOfColor(e,'2;3;','33m')
console.log('用户输入command',this.command)
}
}
});
},
// 建立websocket连接
websocket() {
// WebSocket start
if ('WebSocket' in window) {
//需要修改ip和id
//例如:const url = `ws://192.168.111.222:2375/v1.41/containers/0eb8aafb4e6e/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1`
const url = `ws://你的ip/v1.41/containers/你的id/attach/ws?logs=0&stream=1&stdin=1&stdout=1&stderr=1`
const ws = new WebSocket(url)
this.ws = ws
this.$nextTick(()=>{
this.userWrite()
})
ws.onopen = (event) => {
console.log('已建立连接:',event)
// 输入换行符可让终端显示当前用户的工作路径
ws.send('\n')
// 窗口自适应插件
const fitAddon = new FitAddon.FitAddon();
// 窗口尺寸变化时,终端尺寸自适应
window.onresize = () => {
fitAddon.fit()
}
this.term.loadAddon(fitAddon)
this.term.open(document.getElementById('terminal'));
this.term.focus()
// 自定义终端默认展示内容
this.writeDefaultInfo()
};
ws.onmessage = (event) => {
console.log('接收信息:',event)
//将字符串转换成 Blob对象
const blob = new Blob([event.data], {
type: 'text/plain'
});
//将Blob 对象转换成字符串
const reader = new FileReader();
reader.readAsText(blob, 'utf-8');
reader.onload = (e) => {
// 可以根据返回值判断使用何种颜色或者字体,不过返回值自带了一些字体颜色
this.writeOfColor(reader.result,'0;','37m')
}
};
ws.onerror = (event) => {
console.log('错误信息:', event)
if (wsTime) {
window.clearTimeout(wsTime)
wsTime = null
}
wsTime = window.setTimeout(() => {
this.websocket()
}, 3000)
};
ws.onclose = (event) => {
console.log('已关闭连接:', event)
// if (wsTime) {
// window.clearTimeout(wsTime)
// wsTime = null
// }
// wsTime = window.setTimeout(() => {
// this.websocket()
// }, 3000)
};
} else {
console.log('浏览器不支持 WebSocket..')
}
// WebSocket end
}
}
})
</script>
</html>