Vue3 + xterm + eventSource

2024-03-01 03:44

本文主要是介绍Vue3 + xterm + eventSource,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

xterm 是一个使用 typescript 编写的前端终端组件,可以在浏览器中实现一个命令行终端应用,通常与 websocket一起使用。

一、安装

pnpm install xterm
or
yarn add xterm
or
pnpm install xterm

二、代码实现: 实现日志展示

<template><a-modal class="task-log-dialog" :title="title" :visible="visible" :footer="false" @cancel="onCancel" width="1200px" :mask-closable="false"><div class="main-box"><div class="top-box flex-row-start-center"><a-input v-model:value="grep" placeholder="Filter(regexp)..." size="small" allow-clear @input="searchLog"></a-input><a-input v-model:value="podName" placeholder="podName" size="small" allow-clear @input="searchLog"></a-input></div><div class="content-box"><div ref="terminal" id="terminal" v-loading="loading" element-loading-text="拼命加载中"></div></div><div class="bottom-box">Logs may not appear for pods that are deleted.</div></div></a-modal>
</template><script lang="ts" setup>
import { ref, watch } from 'vue'
import useSystemStore from '@/store/modules/system'
import { debounce } from '@/utils/common'
import { Terminal } from 'xterm'
import { FitAddon } from 'xterm-addon-fit'
import 'xterm/css/xterm.css'type propsType = {currentTask: {projectUuid: stringname: stringpodName: stringgrep: stringfollow: boolean}
}
const props = defineProps<propsType>()
const title = ref<string>('构建日志')
const visible = ref<boolean>(false)
const grep = ref<string>('')
const podName = ref<string>('')
const showModel = () => {visible.value = true
}
defineExpose({showModel
})
const emit = defineEmits(['hide'])
const onCancel = () => {visible.value = falseeventSource.value?.close()term.value?.reset()term.value?.clear()if (terminal.value?.innerHTML) {terminal.value.innerHTML = ''terminal.value = null}emit('hide')
}const baseUrl = import.meta.env.VITE_APP_BASE_URL
const eventSource = ref<EventSource | null>(null)
const getLog = async () => {if (!props.currentTask.name) returninitTerm()createEventSource()
}
const createEventSource = () => {eventSource.value = new EventSource(`${baseUrl}/v1/projects/${useSystemStore().projectUuid}/tasks/${props.currentTask.name}/log?podName=${podName.value}&grep=${grep.value}&follow=true`)eventSource.value.onopen = event => {loading.value = falseterm.value?.clear()console.log('onopen', event)}eventSource.value.onmessage = event => {term.value?.clear()if (eventSource.value?.readyState === 1 && !JSON.parse(event.data).result?.completed) {const eventData = JSON.parse(event.data).resultloading.value = falseterm.value?.write(eventData.PodName + ': ' + eventData.Content + '\r\n')}if (eventSource.value?.readyState === 1 && JSON.parse(event.data).result?.completed) {console.log('complete')eventSource.value?.close()}}eventSource.value.onerror = event => {console.log('error', event)eventSource.value?.close()}
}const terminal = ref<HTMLElement | null>(null)
const fitAddon = new FitAddon()
const loading = ref(true)
const term = ref<null | Terminal>(null)
const initTerm = () => {if (!term.value) {term.value = new Terminal({fontSize: 14,scrollback: 999999999999,allowTransparency: true,fontFamily: 'Monaco, Menlo, Consolas, Courier New, monospace',rows: 40,disableStdin: true, //是否应禁用输入cursorStyle: 'underline',cursorBlink: false,theme: {foreground: '#fff',background: '#000',cursor: 'help'}})}setTimeout(() => {term.value?.open(terminal.value as HTMLElement)term.value?.clear()term.value?.loadAddon(fitAddon)fitAddon.fit()}, 5)
}const searchLog = debounce(() => {term.value?.clear()terminal.value = nullgetLog()
}, 1000)watch(visible, value => {if (value) {title.value = '构建日志 - ' + props.currentTask.namegetLog()} else {eventSource.value?.close()term.value?.reset()term.value?.clear()if (terminal.value?.innerHTML) {terminal.value.innerHTML = ''terminal.value = null}}
})
</script><style lang="less">
.task-log-dialog {.main-box {width: 1152px;.top-box {margin-bottom: 20px;height: 30px;.ant-input-affix-wrapper,.ant-select-selector {width: 280px;height: 30px;margin-right: 20px;}}.content-box {.content {width: 100%;}}.bottom-box {margin-top: 30px;}}
}
</style>

三、效果如下

在这里插入图片描述

这篇关于Vue3 + xterm + eventSource的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/761114

相关文章

Vue项目中Element UI组件未注册的问题原因及解决方法

《Vue项目中ElementUI组件未注册的问题原因及解决方法》在Vue项目中使用ElementUI组件库时,开发者可能会遇到一些常见问题,例如组件未正确注册导致的警告或错误,本文将详细探讨这些问题... 目录引言一、问题背景1.1 错误信息分析1.2 问题原因二、解决方法2.1 全局引入 Element

详解如何在React中执行条件渲染

《详解如何在React中执行条件渲染》在现代Web开发中,React作为一种流行的JavaScript库,为开发者提供了一种高效构建用户界面的方式,条件渲染是React中的一个关键概念,本文将深入探讨... 目录引言什么是条件渲染?基础示例使用逻辑与运算符(&&)使用条件语句列表中的条件渲染总结引言在现代

详解Vue如何使用xlsx库导出Excel文件

《详解Vue如何使用xlsx库导出Excel文件》第三方库xlsx提供了强大的功能来处理Excel文件,它可以简化导出Excel文件这个过程,本文将为大家详细介绍一下它的具体使用,需要的小伙伴可以了解... 目录1. 安装依赖2. 创建vue组件3. 解释代码在Vue.js项目中导出Excel文件,使用第三

Java实现Excel与HTML互转

《Java实现Excel与HTML互转》Excel是一种电子表格格式,而HTM则是一种用于创建网页的标记语言,虽然两者在用途上存在差异,但有时我们需要将数据从一种格式转换为另一种格式,下面我们就来看看... Excel是一种电子表格格式,广泛用于数据处理和分析,而HTM则是一种用于创建网页的标记语言。虽然两

vue解决子组件样式覆盖问题scoped deep

《vue解决子组件样式覆盖问题scopeddeep》文章主要介绍了在Vue项目中处理全局样式和局部样式的方法,包括使用scoped属性和深度选择器(/deep/)来覆盖子组件的样式,作者建议所有组件... 目录前言scoped分析deep分析使用总结所有组件必须加scoped父组件覆盖子组件使用deep前言

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

React实现原生APP切换效果

《React实现原生APP切换效果》最近需要使用Hybrid的方式开发一个APP,交互和原生APP相似并且需要IM通信,本文给大家介绍了使用React实现原生APP切换效果,文中通过代码示例讲解的非常... 目录背景需求概览技术栈实现步骤根据 react-router-dom 文档配置好路由添加过渡动画使用

使用Vue.js报错:ReferenceError: “Vue is not defined“ 的原因与解决方案

《使用Vue.js报错:ReferenceError:“Vueisnotdefined“的原因与解决方案》在前端开发中,ReferenceError:Vueisnotdefined是一个常见... 目录一、错误描述二、错误成因分析三、解决方案1. 检查 vue.js 的引入方式2. 验证 npm 安装3.

vue如何监听对象或者数组某个属性的变化详解

《vue如何监听对象或者数组某个属性的变化详解》这篇文章主要给大家介绍了关于vue如何监听对象或者数组某个属性的变化,在Vue.js中可以通过watch监听属性变化并动态修改其他属性的值,watch通... 目录前言用watch监听深度监听使用计算属性watch和计算属性的区别在vue 3中使用watchE

python解析HTML并提取span标签中的文本

《python解析HTML并提取span标签中的文本》在网页开发和数据抓取过程中,我们经常需要从HTML页面中提取信息,尤其是span元素中的文本,span标签是一个行内元素,通常用于包装一小段文本或... 目录一、安装相关依赖二、html 页面结构三、使用 BeautifulSoup javascript