前端终端组件Xterm.js使用方法
xterm 是一个使用 TypeScript 编写的前端终端组件,可以直接在浏览器中实现一个命令行终端应用。主要特性:终端应用程序正常工作:Xterm.js适用于大多数终端应用程序,如bash,vim和tmux,这包括对基于curses的应用程序和鼠标事件支持的支持Performant:Xterm.js 非常快,它甚至还包括一个GPU加速的渲染器。丰富的 unicode 支持:支持CJK,表情符号
·
xterm 是一个使用 TypeScript 编写的前端终端组件,可以直接在浏览器中实现一个命令行终端应用。
主要特性:
终端应用程序正常工作:Xterm.js适用于大多数终端应用程序,如bash,vim和tmux,这包括对基于curses的应用程序和鼠标事件支持的支持
Performant:Xterm.js 非常快,它甚至还包括一个GPU加速的渲染器。
丰富的 unicode 支持:支持CJK,表情符号和IME。
自包含:零依赖性。
可访问:可以使用screenReaderMode选项打开屏幕阅读器支持。
还有更多:链接,主题,插件,记录良好的API等。
使用方法:
一、安装:
cnpm i xterm@4.6.0 -S
cnpm i xterm-addon-fit@0.4.0 -S
二、组件中使用:
import React from 'react';
import { Terminal } from 'xterm';
import 'xterm/css/xterm.css';
class WebSSH extends React.Component {
constructor(props) {
super(props);
this.socket = null;
this.term = new Terminal();
this.container = null;
this.input = null;
this.state = {
visible: false,
uploading: false,
managerDisabled: true,
host: {},
percent: 0
}
}
componentDidMount() {
//alert(document.getElementById("terminal").offsetHeight);
var term = new Terminal({
rendererType: "canvas", //渲染类型
rows: Math.ceil((document.getElementById("terminal").clientHeight-100)/14), //行数
convertEol: true, //启用时,光标将设置为下一行的开头
scrollback: 10,//终端中的回滚量
disableStdin: false, //是否应禁用输入。
cursorStyle: 'underline', //光标样式
cursorBlink: true, //光标闪烁
theme: {
foreground: 'yellow', //字体
background: '#060101', //背景色
cursor: 'help',//设置光标
}
});
term.open(document.getElementById('terminal'));
term.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ');
if (term._initialized) {
return
}
term._initialized = true
term.prompt = () => {
term.write('\r\n$ ')
}
term.writeln('Welcome to xterm.js')
term.writeln('This is a local terminal emulation, without a real terminal in the back-end.')
term.writeln('Type some keys and commands to play around.')
term.writeln('')
term.prompt()
const webSocket = new WebSocket('ws://localhost:9000');//建立通道
// xterm.4.x 输入
term.onKey(e => {
const ev = e.domEvent
const printable = !ev.altKey && !ev.altGraphKey && !ev.ctrlKey && !ev.metaKey
if (ev.keyCode === 13) {
term.prompt()
} else if (ev.keyCode === 8) {
// Do not delete the prompt
if (term._core.buffer.x > 2) {
term.write('\b \b')
}
} else if (printable) {
term.write(e.key);
webSocket.send(e.key);
}
})
//返回
webSocket.onmessage = function (evt) {
term.write(evt.data);
};
// xterm3.x
// function runFakeTerminal() {
// if (term._initialized) {
// return;
// }
// term._initialized = true;
// term.prompt = () => {
// term.write('\r\n$ ');
// };
// term.writeln('Welcome to xterm.js');
// term.writeln('This is a local terminal emulation, without a real terminal in the back-end.');
// term.writeln('Type some keys and commands to play around.');
// term.writeln('');
// term.prompt();
// term.on('key', function (key, ev) {
// const printable = !ev.altKey && !ev.altGraphKey && !ev.ctrlKey && !ev.metaKey;
// console.log(key,ev.keyCode);
// console.log(term._core.buffer.x);
// if (ev.keyCode === 13) {
// term.prompt();
// } else if (ev.keyCode === 8) {
// // Do not delete the prompt
// if (term._core.buffer.x > 2) {
// term.write('\b \b');
// }
// } else if (printable) {
// term.write(key);
// }
// });
// term.on('paste', function (data) {
// term.write(data);
// });
// }
// runFakeTerminal();
}
render() {
return (
<div id="terminal" style={{height: "100%"}}></div> //terminal容器
)
}
}
export default WebSSH
import React from 'react';
import { Button } from 'antd';
import { AuthDiv } from 'components';
import { Terminal } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';
import FileManager from './FileManager';
import { http, X_TOKEN } from 'libs';
import 'xterm/css/xterm.css';
import styles from './index.module.css';
class WebSSH extends React.Component {
constructor(props) {
super(props);
this.id = props.match.params.id;
this.socket = null;
this.term = new Terminal();
this.container = null;
this.input = null;
this.state = {
visible: false,
uploading: false,
managerDisabled: true,
host: {},
percent: 0
}
}
componentDidMount() {
this._fetch();
const fitPlugin = new FitAddon();
this.term.loadAddon(fitPlugin);
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
this.socket = new WebSocket(`${protocol}//${window.location.host}/api/ws/ssh/${this.id}/?x-token=${X_TOKEN}`);
this.socket.onmessage = e => this._read_as_text(e.data);
this.socket.onopen = () => {
this.term.open(this.container);
this.term.focus();
fitPlugin.fit();
};
this.socket.onclose = e => {
if (e.code === 3333) {
window.location.href = "about:blank";
window.close()
} else {
setTimeout(() => this.term.write('\r\nConnection is closed.\r\n'), 200)
}
};
this.term.onData(data => this.socket.send(JSON.stringify({data})));
this.term.onResize(({cols, rows}) => {
this.socket.send(JSON.stringify({resize: [cols, rows]}))
});
window.onresize = () => fitPlugin.fit()
}
_read_as_text = (data) => {
const reader = new window.FileReader();
reader.onload = () => this.term.write(reader.result);
reader.readAsText(data, 'utf-8')
};
handleShow = () => {
this.setState({visible: !this.state.visible})
};
_fetch = () => {
http.get(`/api/host/?id=${this.id}`)
.then(res => {
document.title = res.name;
this.setState({host: res, managerDisabled: false})
})
};
render() {
const {host, visible, managerDisabled} = this.state;
return (
<div className={styles.container}>
<div className={styles.header}>
<div>{host.name} | {host.username}@{host.hostname}:{host.port}</div>
<AuthDiv auth="host.console.manager">
<Button disabled={managerDisabled} type="primary" icon="folder-open"
onClick={this.handleShow}>文件管理器</Button>
</AuthDiv>
</div>
<div className={styles.terminal}>
<div ref={ref => this.container = ref}/>
</div>
<FileManager id={this.id} visible={visible} onClose={this.handleShow}/>
</div>
)
}
}
export default WebSSH
更多推荐
已为社区贡献11条内容
所有评论(0)