惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
V2EX
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
WordPress大学
WordPress大学
罗磊的独立博客
小众软件
小众软件
I
InfoQ
Y
Y Combinator Blog
宝玉的分享
宝玉的分享
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Hugging Face - Blog
Hugging Face - Blog
MyScale Blog
MyScale Blog
博客园 - 聂微东
Microsoft Security Blog
Microsoft Security Blog
H
Help Net Security
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园_首页
S
SegmentFault 最新的问题
博客园 - 三生石上(FineUI控件)
P
Proofpoint News Feed
博客园 - 司徒正美
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Azure Blog
Microsoft Azure Blog
Jina AI
Jina AI
N
Netflix TechBlog - Medium

Dr34m's Blog

I Expect You To Die(我希望你死) 1,2,3 完整中文攻略 Linux换国内源 && docker安装 && 换加速镜像 Vue3 + Element-Plus 极简速查 随笔 pyinstaller打包的程序执行报错Failed to extract xxxx decompression resulted in return code -1 taoSync排除项简易教程 apscheduler的cron配置项 如何在绿联NAS中使用TaoSync同步我的文件到各个网盘 GB28181抓包记录 JS计算字节大小,把字节转换为KB/MB/GB/TB等 在Python中使用onvif管理摄像头,包括设备发现,获取RTSP地址,获取设备信息,截图,云台控制与缩放,设置时间 编写bat脚本实现对vue项目构建并压缩 内网穿透工具frp快速使用 CentOS 7.9 安装基础开发环境jdk redis nacos nginx mysql Pyinstaller 逆向 VUE实现复制与粘贴_获取剪切板内容 child_process exec 中文乱码 Windows&Linux 解决方法 yum 更新 gcc CentOS安装并使用conda 将fluid主题博客的静态资源由第三方改为本地存储 一个上手即用的通用公众号/小程序/h5/app框架 python批量转化doc到docx SpringBoot单元测试注入空指针 TensorFlow 预测出现NaN的一种可能以及解决方法 随笔 python归一化数据 windows下python安装sasl遇到的问题及解决 将对象List中的某个字段放到新的List中[转载] Python http.server 本地服务支持跨域 TensorFlow入门
Electron + xterm.js + node-pty + vue 实现本地终端
Dr3@m · 2022-08-25 · via Dr34m's Blog

本文介绍一种简单方法,实现本地终端程序。

项目已上传Github https://github.com/dr34m-cn/electron-term-demo

核心代码

服务提供处:background.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
...

import {
app,
protocol,
BrowserWindow,
ipcMain
} from 'electron'

const pty = require("node-pty");
const os = require("os");
const shell = os.platform() === "win32" ? "powershell.exe" : "bash";

...

// 创建终端
ipcMain.handle("terminal-create", (event) => {
let term = pty.spawn(shell, [], {
name: "xterm-color",
cwd: process.env.PWD,
env: process.env
});
const pid = term.pid;
const channels = ["terminal-incomingData-" + pid, "terminal-keystroke-" + pid, "terminal-resize-" + pid, "terminal-close-" + pid];
// 命令反馈
term.onData(function(data) {
win.webContents.send(channels[0], data);
})
// 命令输入
ipcMain.on(channels[1], (event, key) => {
term.write(key);
});
// 尺寸调整
ipcMain.on(channels[2], (event, cols, rows) => {
term.resize(cols, rows);
});
// 终端关闭
ipcMain.on(channels[3], (event) => {
term.kill();
ipcMain.removeAllListeners([channels[1], channels[2], channels[3]]);
});
return pid;
});

封装处:term.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<template>
<div class="term" :id="'terminal' + id">
</div>
</template>
<script>
import 'xterm/css/xterm.css';
const ipc = require("electron").ipcRenderer;
import {
Terminal
} from 'xterm';
import {
FitAddon
} from 'xterm-addon-fit';
export default {
props: {
id: {
type: Number
},
showFlag: {
type: Boolean
}
},
watch: {
showFlag: {
handler: function(newVal, oldVal) {
this.fitSize();
},
immediate: true
}
},
name: 'Term',
data() {
return {
xterm: null,
fitAddon: null,
channels: null
};
},
beforeDestroy() {
this.destoryTerm();
},
mounted() {
this.initConnect();
},
methods: {
initConnect() {
this.destoryTerm();
let that = this;
ipc.invoke('terminal-create').then(res => {
let pid = res;
let xterm = new Terminal();
let fitAddon = new FitAddon();
xterm.loadAddon(fitAddon);
xterm.open(document.getElementById('terminal' + this.id));
that.xterm = xterm;
that.fitAddon = fitAddon;
that.channels = ["terminal-incomingData-" + pid, "terminal-keystroke-" + pid, "terminal-resize-" + pid, "terminal-close-" + pid];
xterm.onData((data) => {
ipc.send(that.channels[1], data);
})
xterm.onResize((size) => {
ipc.send(that.channels[2], size.cols, size.rows);
})
ipc.on(that.channels[0], (event, data) => {
xterm.write(data);
});
window.onresize = function() {
that.fitSize();
}
that.fitSize();
xterm.focus();
})
},
destoryTerm() {
if (this.xterm) {
this.xterm.dispose();
this.xterm = null;
}
if (this.fitAddon) {
this.fitAddon.dispose();
this.fitAddon = null;
}
if (this.channels) {
ipc.send(this.channels[3]);
ipc.removeAllListeners(this.channels[0]);
this.channels = null;
}
},
fitSize() {
if (this.showFlag && this.fitAddon) {
this.fitAddon.fit();
}
}
}
}
</script>
<style>
</style>

调用处:App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<template>
<div id="app">
<term :id="1" :showFlag="true" class="term"></term>
</div>
</template>
<script>
import term from '@/components/term'
export default {
name: 'App',
components: {
term
},
data() {
return {};
},
created() {},
methods: {}
}
</script>
<style>
body {
margin: 0;
padding: 0;
background: #000000;
}
.term {
width: 100vw;
height: 100vh;
}
::-webkit-scrollbar {
/*滚动条整体样式*/
width: 10px;
/*高宽分别对应横竖滚动条的尺寸*/
height: 10px;
}

::-webkit-scrollbar-thumb {
background-color: #FFF;
}

::-webkit-scrollbar-track {
/*滚动条里面轨道*/
background: #000;
}
</style>

推荐版本nodejs 14.X

需要满足node-pty使用依赖,摘录在最后

启动方式:

首次

1
2
3
npm install
npm run rebuild
npm run serve

之后

1
npm run serve

效果如下

node-pty使用依赖摘录如下

Dependencies

Node.JS 12+ or Electron 8+ is required to use node-pty.

Linux (apt)

1
sudo apt install -y make python build-essential

macOS

Xcode is needed to compile the sources, this can be installed from the App Store.

Windows

npm install requires some tools to be present in the system like Python and C++ compiler. Windows users can easily install them by running the following command in PowerShell as administrator. For more information see https://github.com/felixrieseberg/windows-build-tools:

1
npm install --global --production windows-build-tools

The following are also needed:

  • Windows SDK - only the “Desktop C++ Apps” components are needed to be installed