当前位置: 首页 > news >正文

客户端(浏览器)vue3本地预览txt,doc,docx,pptx,pdf,xlsx,csv,

预览文件

  • 1、入口文件preview/index.vue
  • 2、预览txt
  • 3、预览doc
  • 4、预览pdf
  • 5、预览pptx
  • 6、预览xlsx
  • 7、预览csv

1、入口文件preview/index.vue

预览样式,如pdf
在这里插入图片描述

文件目录如图所示:
在这里插入图片描述
代码如下

<template><div class="preview-wrap" ref="previewDom" v-if="hasPreviewFlag"><DocxPreview v-if="fileType === 'docx' || fileType === 'doc'" :file-data="fileData" /><PdfPreview v-else-if="fileType === 'pdf'" :file-data="fileData" /><TxtPreview v-else-if="fileType === 'txt'" :file-data="fileData" /><XlsxPreview v-else-if="fileType === 'xlsx'" :file-data="fileData" /><PptxPreview v-else-if="fileType === 'pptx'" :file-data="fileData" :file-id="row.id"/><CsvPreview v-else-if="fileType === 'csv'" :file-data="fileData" file-type="csv" /><div v-else><el-resulticon="error"title="提示"sub-title="文件不存在或者异常"/></div></div>
</template><script setup>
import { ElMessage } from 'element-plus'
import DocxPreview from './components/DocxPreview.vue'
import PdfPreview from './components/PdfPreview.vue'
import TxtPreview from './components/TxtPreview.vue'
import XlsxPreview from './components/XlsxPreview.vue'
import PptxPreview from './components/PptxPreview.vue'
import CsvPreview from './components/CsvPreview.vue'
import { ref, onMounted, defineProps } from 'vue'const props = defineProps({row: {type: Object,default: () => {},},
})
const filePath = ref('')
const fileType = ref('')
const fileData = ref(null)
const hasPreviewFlag = ref(true)onMounted(() => {// console.log('row', props.row)const typeList = ['docx', 'doc', 'txt', 'pdf', 'xlsx', 'pptx', 'csv'] // 目前支持的类型filePath.value = props.row.cached_file_path || ''filePath.value = 'D:\\work\\test.txt' || props.row // 调试用// filePath.value = 'D:\\work\\test.docx' || props.row// filePath.value = 'D:\\work\\test.xlsx' || props.row// filePath.value = 'D:\\work\\test.csv' || props.row// filePath.value = 'D:\\work\\test.pdf' || props.row// filePath.value = 'D:\\work\\test.pptx'fileType.value = (filePath.value.split('.').pop() || props.row.file_type).toLowerCase()if (!typeList.includes(fileType.value)) {return ElMessage.error('此文件不支持预览')}if (typeList.includes(fileType.value)) {hasPreviewFlag.value = truewindow.electronAPI?.readFileSend(filePath.value) // 通过绝对路径获取文件流信息} else {hasPreviewFlag.value = false}
})
// 这里根据客户端的主进程和渲染进行通过文件的绝对路径获取文件流
window.electronAPI?.readFileReceive((event, data) => {// console.log('arraybuffer---->', data) // 将arraybuffer转换成bolb形式fileData.value = new Blob([data])
})
</script><style lang="scss">
.preview-wrap {height: calc(100vh - 130px);overflow: auto;z-index: 1;position: relative;padding: 8px;background: white;border: 1px solid #ccc;
}::-webkit-scrollbar {width: 0 !important;
}::-webkit-scrollbar {width: 0 !important;height: 0;
}
</style>

preload.js

  // 跨窗口通信方法-读取文件readFileSend: (...args) => ipcRenderer.send("read-file", ...args),readFileReceive: (cb) => ipcRenderer.on('read-file', cb),

main.js

// 通过文件的绝对路径获取文件流
ipcMain.on('read-file', (event, filePath) => {const currentWindow = BrowserWindow.fromWebContents(event.sender)fs.readFile(filePath, (err, res) => {if (err) {console.log('read-file', err)} else { currentWindow && currentWindow.webContents.send('read-file', res)}})
})

2、预览txt

<template><div><pre class="txtViewer">{{ txtContent }}</pre></div>
</template><script setup>
import { ref, watch, toRefs, defineProps } from 'vue'const props = defineProps({fileData: {type: Blob,default: null}
})
const { fileData } = toRefs(props)
const txtContent = ref('')watch(() => fileData.value,(newv, oldv) => {previewFile(newv)}
)
const previewFile = fileData => {const reader = new FileReader();reader.onload = () => {txtContent.value = reader.result;};reader.readAsText(fileData);
}</script><style lang="scss" scoped>
.txtViewer {width: 100%;height: 100%;overflow: auto;margin-bottom: 0;white-space: pre-wrap;
}
</style>

3、预览doc

采用docx-preview

<template><div><div id="docx-content-preview" class="docFile" v-show="!loading"></div></div>
</template><script setup>
import { renderAsync } from 'docx-preview'
import { ref, defineProps, watch, toRefs } from 'vue'const loading = ref(true)
const props = defineProps({fileData: {type: Object,default: () => {},},
})const { fileData } = toRefs(props);watch(() => fileData.value,val => {loading.value = truepreviewfile(val)},{ deep: true }
)
function previewfile(fileData) {// 选择要渲染的元素const docFile = document.getElementsByClassName('docFile')// const blob = new Blob([fileData])// 用docx-preview渲染renderAsync(fileData, docFile[0]).then(res => {console.log('res---->', res)loading.value = false})
}
</script><style lang="scss" scoped>
#docx-content-preview {min-height: 200px;overflow-x: hidden;padding: 10px;
}
.docFile {:deep(.docx-wrapper) {background: white;}:deep(section) {width: 100% !important;box-shadow: none;}
}:deep(.docx-wrapper > section.docx) {width: 100% !important;padding: 0rem !important;min-height: auto !important;box-shadow: none;margin-bottom: 0;article {overflow: auto;}
}
</style>

4、预览pdf

实现的方式有多种,可采用pdfjs-dist、或
pdf.worker.min.mj可在官网上下载

<template><div style="position:relative;"><div style="text-align: center; position: relative" ref="pdfViewer" class="pdfViewer"></div></div>
</template><script setup>
import * as pdfjsLib from 'pdfjs-dist'
import { ref, watch, toRefs } from 'vue'
pdfjsLib.GlobalWorkerOptions.workerSrc = "./pdf.worker.min.mjs";const props = defineProps({fileData: {type: Blob,default: null}
})
const { fileData } = toRefs(props);
const pdfViewer = ref()
const loading = ref(true)
const allParagraphs = ref([])
const canvasHistory = ref({})
// const scale = 1.5
const scale = window.devicePixelRatio > 1.3 ? 1 : 1.5watch(() => fileData.value,async (newVal, oldVal) => {clearRec();previewFile(newVal)},{ deep: true }
)const previewFile = (fileData) => {getUint8ArrayData(fileData).then((uint8Array) => {renderPdf(uint8Array)})
}const getUint8ArrayData = (blob) => {return new Promise((resolve, reject) => {// 使用FileReader读取Blob对象const fileReader = new FileReader()fileReader.onload = function () {// 读取完成后,result属性将包含Uint8Array数据const uint8Array = new Uint8Array(fileReader.result)resolve(uint8Array)}fileReader.onerror = function () {console.error('读取Blob时发生错误')reject(new Error('读取Blob时发生错误'))}// 开始读取BlobfileReader.readAsArrayBuffer(blob)})
}
const renderPdf = async (uint8Array) => {const loadingTask = pdfjsLib.getDocument(uint8Array)const pdf = await loadingTask.promisefor (let i = 1; i <= pdf.numPages; i++) {await renderPage(pdf, i)}loading.value = false;
}const renderPage = async (pdf, pageNumber) => {// 构造canvasconst canvas = document.createElement('canvas')canvas.style = 'direction: ltr;position: relative'canvas.id = `canvas_page_${pageNumber}`canvas.className = `canvas_page`// 构造文本层const layerDiv = document.createElement('div')layerDiv.style ='position: absolute;left: 0;top: 0;right: 0;bottom: 0;overflow: hidden;opacity: 0.4;line-height: 1.0;'layerDiv.id = `canvas_layer_page_${pageNumber}`layerDiv.className = 'canvas-layer'const div = document.createElement('div')div.style = 'width: fit-content;margin: 0 auto;position:relative; border: 1px solid #ccc; margin-bottom: 8px;'div.id = `page-container-${pageNumber}`div.className = `page-container`div.appendChild(canvas)// div.appendChild(layerDiv)pdfViewer.value.appendChild(div)const page = await pdf.getPage(pageNumber)const viewport = page.getViewport({ scale })// Support HiDPI-screens.const outputScale = window.devicePixelRatio || 1// Prepare canvas using PDF page dimensionsconst context = canvas.getContext('2d')canvas.width = Math.floor(viewport.width * outputScale)canvas.height = Math.floor(viewport.height * outputScale)canvas.style.width = Math.floor(viewport.width) + 'px'canvas.style.height = Math.floor(viewport.height) + 'px'canvas.style.maxWidth = 1200 + 'px'  // 解决pdf文档宽度过长导致样式错乱const transform =outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null// Render PDF page into canvas contextconst renderContext = {canvasContext: context,transform,viewport,}await page.render(renderContext).promise// 存入画布渲染pdf的状态,用于还原canvasHistory.value[pageNumber] = canvas.toDataURL()const textContent = await page.getTextContent()// Pass the data to the method for rendering of text over the pdf canvas.// const task = pdfjsLib.renderTextLayer({//   textContentSource: page.streamTextContent(),//   container: layerDiv,//   viewport,//   textDivs: [],// })// await task.promise// 处理得到每页的paragraphconst pageParagraphs = handleParagraphs(pageNumber,canvas,viewport,textContent.items)await clearRec()allParagraphs.value = allParagraphs.value.concat(pageParagraphs)
}const handleParagraphs = (pageNumber, canvas, viewport, textContent) => {const newArr = groupByTransform(pageNumber,(textContent || []).filter((item) => !!item.str.trim()))const paragraphs = newArr.map((item) => {return {pageNumber,canvas,viewport,content: item.map((it) => it.str).reduce((a, b) => {return a + b}, ''),items: item,}})return paragraphs
}
const groupByTransform = (pageNumber, array) => {const result = []const map = new Map()array.forEach((obj) => {const key = obj.transform[5]if (!map.has(key)) {map.set(key, [obj])} else {map.get(key).push(obj)}})map.forEach((value) => {result.push(value)})return result
}
const clearRec = async () => {for (const key in canvasHistory.value) {const canvas = document.getElementById(`canvas_page_${key}`)if (canvas) {const context = canvas.getContext("2d");const canvasPic = await loadPdfImage(key)context.drawImage(canvasPic, 0, 0);} else {console.log('获取节点失败', `canvas_page_${key}`)}}
}const loadPdfImage = (index) => {return new Promise((resolve, reject) => {const canvasPic = new Image();canvasPic.src = canvasHistory.value[index]canvasPic.onload = () => {// 当图像加载完成后进行resolve,确保drawImage执行成功resolve(canvasPic)}canvasPic.onerror = () => {reject(new Error('加载还原图像失败'))}})
}
</script><style lang="scss" scoped>
.pdfViewer {min-height: 100%;:deep(.canvas-layer > span) {color: transparent;position: absolute;white-space: pre;cursor: text;transform-origin: 0% 0%;background: transparent;z-index: 1;}:deep(.page-container) {width: 100% !important;.canvas_page {width: 100% !important;height: 100% !important;}}
}
</style>

5、预览pptx

6、预览xlsx

7、预览csv

相关文章:

客户端(浏览器)vue3本地预览txt,doc,docx,pptx,pdf,xlsx,csv,

预览文件 1、入口文件preview/index.vue2、预览txt3、预览doc4、预览pdf5、预览pptx6、预览xlsx7、预览csv 1、入口文件preview/index.vue 预览样式&#xff0c;如pdf 文件目录如图所示&#xff1a; 代码如下 <template><div class"preview-wrap" ref&…...

[SZ901]JTAG高速下载设置(53Mhz)

SZ901最高支持JTAG 53MHz的时钟频率&#xff0c;下载bit文件和固化程序的速度提升非常明显。 首先设置参数 1&#xff0c;将JTAG0 分频系数修改为3 2&#xff0c;设置参数&#xff0c;更新参数。&#xff08;完成&#xff09; 打开VIVADO VIVADO 正常识别FPGA&#xff0c;速…...

docker springboot 运维部署详细实例

环境安装 [rootiZbp1dcnzq7pzpg9607m6pZ ~]# docker -v Docker version 26.1.4, build 5650f9b镜像构建 Dockerfile 文件内容 FROM openjdk:8 # Author Info 创建人信息 MAINTAINER ratelcloudfoxmail.com ENV PORT20001 EXPOSE 20001 RUN mkdir /usr/local/ratel-boot-serv…...

Linux 查看目录命令 ls 详细介绍

Linux 和 Unix 系统中 ls 命令是用于列出目录内容。用户可以查看指定目录下的文件和子目录&#xff0c;还可以获取有关这些文件和子目录的详细信息。 基本语法&#xff1a; ls [选项] [目录]如果不指定目录&#xff0c;ls 将列出当前工作目录下的内容。 01、-a 或 --all ls…...

React Native状态管理器Redux、MobX、Context API、useState

Redux、MobX、Context API、useState都是React中用于状态管理的工具&#xff0c;但它们各自有不同的特点和使用场景。 Redux 介绍&#xff1a; Redux是一个JavaScript状态管理库&#xff0c;最初由Dan Abramov和Andrew Clark于2015年开发。它基于Flux架构&#xff0c;强调状态…...

Three.js资源-模型下载网站

在使用 Three.js 进行 3D 开发时&#xff0c;拥有丰富的模型资源库可以大大提升开发效率和作品质量。以下是一些推荐的 Three.js 模型下载网站&#xff0c;它们提供了各种类型的 3D 模型&#xff0c;适合不同项目需求。无论你是需要逼真的建筑模型&#xff0c;还是简单的几何体…...

linux 添加默认网关

在linux 可以使用 route 命令添加默认网关&#xff0c;假设添加的默认网关是192.168.159.2 添加方式如下&#xff1a; route add default gw 192.168.159.2 以上命令只需要把add 改成 del &#xff0c;就能删除刚才添加的路由 route del default gw 192.168.159.2 #该命…...

【学习笔记】深入浅出详解Pytorch中的View, reshape, unfold,flatten等方法。

文章目录 一、写在前面二、Reshape&#xff08;一&#xff09;用法&#xff08;二&#xff09;代码展示 三、Unfold&#xff08;一&#xff09;torch.unfold 的基本概念&#xff08;二&#xff09;torch.unfold 的工作原理&#xff08;三&#xff09; 示例代码&#xff08;四&a…...

CTFHUB-web(SSRF)

内网访问 点击进入环境&#xff0c;输入 http://127.0.0.1/flag.php 伪协议读取文件 /?urlfile:///var/www/html/flag.php 右击查看页面源代码 端口扫描 1.根据题目提示我们知道端口号在8000-9000之间,使用bp抓包并进行爆破 POST请求 点击环境&#xff0c;访问flag.php 查看页…...

分解质因数

给定 n个正整数 &#xff0c;将每个数分解质因数&#xff0c;并按照质因数从小到大的顺序输出每个质因数的底数和指数。 输入格式 第一行包含整数 n 接下来 n行&#xff0c;每行包含一个正整数 。 输出格式 对于每个正整数 &#xff0c;按照从小到大的顺序输出其分解质因数后&…...

前景物体提取

参考&#xff1a;精选课&#xff1a;C完整的实现双目摄像头图像采集、双目摄像头畸变矫正、前景物体提取、生成视差图、深度图、PCL点云图 前景物体提取是计算机视觉中的一个重要技术&#xff0c;可以用于视频监控、虚拟现实和计算机视觉等领域。 1.前景物体提取的原理 前景…...

Kotlin复习

一、Kotlin类型 1.整数 2.浮点 显示转换&#xff1a; 所有数字类型都支持转换为其他类型&#xff0c;但是转换前会检测长度。 toByte(): Byte toShort(): Short toInt(): Int toLong(): Long toFloat(): Float toDouble(): Double 不同进制的数字表示方法&#xff08;为了提高…...

【AI日记】24.12.17 kaggle 比赛 2-6 | 把做饭看成一种游戏 | 咖喱牛肉

【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI日记】 工作 参加&#xff1a;kaggle 比赛 Regression with an Insurance Dataset时间&#xff1a;9 小时睡得好很重要 读书 书名&#xff1a;富兰克林自传时间&#xff1a;0.5 小时阅读原因&#xff1a;100 美元纸…...

操作系统(14)请求分页

前言 操作系统中的请求分页&#xff0c;也称为页式虚拟存储管理&#xff0c;是建立在基本分页基础上&#xff0c;为了支持虚拟存储器功能而增加了请求调页功能和页面置换功能的一种内存管理技术。 一、基本概念 分页&#xff1a;将进程的逻辑地址空间分成若干个大小相等的页&am…...

uniapp navigateTo、redirectTo、reLaunch等页面路由跳转方法的区别

uni.switchTab 跳转到 tabBar 页面&#xff0c;并关闭其他所有非 tabBar 页面 // app.json {"tabBar": {"list": [{"pagePath": "index","text": "首页"},{"pagePath": "other","text&…...

模型 A/B测试(科学验证)

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。控制变量法。 1 A/B测试的应用 1.1 Electronic Arts&#xff08;EA&#xff09;《模拟城市》5游戏网站A/B测试 定义目标&#xff1a; Electronic Arts&#xff08;EA&#xff09;在发布新版《模拟城…...

谷歌发布升级版AI视频生成器Veo 2与图像生成器Imagen 3

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

快速掌握源码部署Filebeat

文章目录 1. 裸金属安装1.1 压缩包方式安装1.2 yum方式安装 2. docker安装3. K8s安装 项目使用了Filebeat&#xff0c;现在需要运行在ARM架构的服务器上&#xff0c;但是Filebeat官方没有提供&#xff0c;需要自己编译一份 filebeat等组件的源码地址 https://github.com/elasti…...

C++ 哈希表封装unordered_map 和 unordered_set

1.源码框架 SGI-STL30版本源代码中没有unordered_map和unordered_set&#xff0c;SGI-STL30版本是C11之前的STL 版本&#xff0c;这两个容器是C11之后才更新的。但是SGI-STL30实现了哈希表&#xff0c;只容器的名字是hash_map 和hash_set&#xff0c;他是作为⾮标准的容器出现…...

pymysql 入门

发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【宝藏入口】。 1. 什么是 PyMySQL&#xff1f; PyMySQL 是一个纯 Python 编写的 MySQL 客户端库&#xff0c;可以通过它轻松地在 Python 中连…...

Flutter集成鸿蒙适配三方库:基础级鸿蒙应用开发实践案例

Flutter集成鸿蒙适配三方库&#xff1a;基础级鸿蒙应用开发实践案例 欢迎加入开源鸿蒙跨平台社区&#xff1a;https://openharmonycrossplatform.csdn.net 本文聚焦基础级开发场景&#xff0c;以“Flutter搭建鸿蒙应用集成鸿蒙适配版三方库”为核心&#xff0c;提供一步一操作…...

MySQL 5.7.32 Online DDL避坑指南:如何避免主从延迟和锁等待?

MySQL 5.7.32 Online DDL实战避坑&#xff1a;高并发场景下的零停机表结构变更策略 在数据库运维的日常工作中&#xff0c;表结构变更&#xff08;DDL&#xff09;操作总是让人又爱又恨。特别是当面对千万级数据表时&#xff0c;一个简单的ALTER TABLE操作就可能引发连锁反应—…...

30分钟搞定OpenClaw:Qwen3-4B镜像云端体验与技能测试

30分钟搞定OpenClaw&#xff1a;Qwen3-4B镜像云端体验与技能测试 1. 为什么选择云端体验OpenClaw 上周我在本地尝试部署OpenClaw时&#xff0c;被各种环境依赖和配置问题折磨得够呛。正当我准备放弃时&#xff0c;偶然发现星图平台提供了预置OpenClaw和Qwen3-4B模型的完整镜像…...

智能抢号引擎:5分钟实现资源预约自动化的高效解决方案

智能抢号引擎&#xff1a;5分钟实现资源预约自动化的高效解决方案 【免费下载链接】91160-cli 健康160全自动挂号脚本 项目地址: https://gitcode.com/gh_mirrors/91/91160-cli 在数字化时代&#xff0c;热门资源的抢订总是充满挑战——无论是限量课程报名、热门活动预约…...

Istio Gateway+VirtualService配置不生效?Java服务流量劫持失败的6大隐性原因深度诊断

第一章&#xff1a;Istio GatewayVirtualService配置不生效&#xff1f;Java服务流量劫持失败的6大隐性原因深度诊断Istio 的 Gateway 与 VirtualService 是实现南北向流量治理的核心资源&#xff0c;但 Java 应用在启用 Istio Sidecar 注入后&#xff0c;常出现请求未被 Envoy…...

seo 站群的优缺点是什么

SEO 站群的优缺点解析 在现代的互联网营销中&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;站群是一个重要的概念。SEO 站群是指由多个主题相关的网站组成的集合&#xff0c;这些网站通过某种联系形式运作在一起&#xff0c;以提升整体的搜索引擎排名和流量。虽然 SEO …...

嵌入式AI开发实战:从MCU到模型部署全流程

1. 嵌入式AI开发实战&#xff1a;从入门到项目落地作为一名在嵌入式领域摸爬滚打多年的工程师&#xff0c;我深知AI技术给这个传统行业带来的变革。记得2018年第一次接触基于MCU的简单图像识别时&#xff0c;那种"原来嵌入式设备也能做AI"的震撼感至今难忘。如今&…...

爬虫自动化(DrissionPage)

目录 ?一.介绍: 下载DrissionPage,还是我们熟悉的pip&#xff1a; 环境准备&#xff1a; ?二.基本代码&#xff1a; 它对于的导包和类使用&#xff1a; 窗口的设置&#xff1a; 和获取的页面的滑动&#xff1a; 3.进一步认识DrissionPage&#xff1a; 浏览器可以多开…...

Monaco-Editor插件使用小坑

无法通过鼠标进行选中文本<div id"monacoEditor" class"monacoEditor"></div>外层添加了splinter拖拽组件&#xff0c;导致mousemove事件被拦截&#xff0c;给monaco-editor添加css&#xff1a;pointer-events&#xff1a;auto.monacoEditor .…...

豪鹏科技2025年财报透视:毛利率提升5.2个百分点,费用管控成效显著

豪鹏科技2025年财报透视&#xff1a;毛利率提升5.2个百分点&#xff0c;费用管控成效显著豪鹏科技2025年业绩表现亮眼&#xff0c;全年实现营业收入57亿元至60亿元&#xff0c;同比增长11.58%至17.45%&#xff1b;归母净利润1.95亿元至2.2亿元&#xff0c;同比大幅增长113.69%至…...