98 lines
2.0 KiB
Vue
98 lines
2.0 KiB
Vue
<script lang="ts" setup>
|
||
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue';
|
||
import { FitAddon } from 'xterm-addon-fit';
|
||
import { Terminal } from 'xterm';
|
||
import 'xterm/css/xterm.css';
|
||
const emit = defineEmits(['update:value']);
|
||
const props = defineProps({
|
||
/**终端ID,必传 */
|
||
id: {
|
||
type: String,
|
||
required: true,
|
||
},
|
||
/**窗口单行字符数 */
|
||
cols: {
|
||
type: Number,
|
||
default: 80,
|
||
},
|
||
/**窗口行数 */
|
||
rows: {
|
||
type: Number,
|
||
default: 40,
|
||
},
|
||
/**信息 */
|
||
value: {
|
||
type: String,
|
||
default: '',
|
||
},
|
||
});
|
||
|
||
/**终端输入DOM节点实例对象 */
|
||
const terminalDom = ref<HTMLElement | undefined>(undefined);
|
||
|
||
/**终端输入实例对象 */
|
||
const terminal = ref<any>(null);
|
||
|
||
/**终端输入渲染 */
|
||
function handleRanderXterm(container: HTMLElement | undefined) {
|
||
if (!container) return;
|
||
const xterm = new Terminal({
|
||
cols: props.cols,
|
||
rows: props.rows,
|
||
lineHeight: 1.2,
|
||
fontSize: 12,
|
||
fontFamily: "Monaco, Menlo, Consolas, 'Courier New', monospace",
|
||
theme: {
|
||
background: '#000000',
|
||
},
|
||
cursorBlink: false, // 光标闪烁
|
||
cursorStyle: 'block',
|
||
scrollback: 1000,
|
||
scrollSensitivity: 15,
|
||
tabStopWidth: 4,
|
||
disableStdin: true, // 禁止输入
|
||
});
|
||
// 挂载
|
||
xterm.open(container);
|
||
// 自适应尺寸
|
||
const fitAddon = new FitAddon();
|
||
xterm.loadAddon(fitAddon);
|
||
|
||
// 创建 ResizeObserver 实例
|
||
var observer = new ResizeObserver(entries => {
|
||
fitAddon.fit();
|
||
});
|
||
// 监听元素大小变化
|
||
observer.observe(container);
|
||
|
||
terminal.value = xterm;
|
||
}
|
||
|
||
onMounted(() => {
|
||
nextTick(() => {
|
||
handleRanderXterm(terminalDom.value);
|
||
// 初始发送命令
|
||
if (typeof props.value === 'string') {
|
||
terminal.value.write(props.value);
|
||
}
|
||
});
|
||
});
|
||
|
||
onBeforeUnmount(() => {
|
||
if (terminal.value != null) {
|
||
terminal.value.dispose();
|
||
}
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<div ref="terminalDom" :id="id" class="terminal"></div>
|
||
</template>
|
||
|
||
<style lang="css" scoped>
|
||
.terminal {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
</style>
|