客户端(浏览器)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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/491327.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

luckysheet与superslide冲突解决

[现象]控制台报错、界面无法操作 $是jquery。查看源码&#xff0c;发现mousewheel方法来自插件mousewheel&#xff0c;luckysheet初始应该会将mousewheel挂载在jquery上。 在控制台打印jquery取dom及其方法&#xff0c;结果如下&#xff1a; 不存在mousewheel方法&#xff0c…

MongoDB(上)

MongoDB 基础 MongoDB 是什么&#xff1f; MongoDB 是一个基于 分布式文件存储 的开源 NoSQL 数据库系统&#xff0c;由 C 编写的。MongoDB 提供了 面向文档 的存储方式&#xff0c;操作起来比较简单和容易&#xff0c;支持“无模式”的数据建模&#xff0c;可以存储比较复杂…

搭建Tomcat(四)---Servlet容器

目录 引入 Servlet容器 一、优化MyTomcat ①先将MyTomcat的main函数搬过来&#xff1a; ②将getClass()函数搬过来 ③创建容器 ④连接ServletConfigMapping和MyTomcat 连接&#xff1a; ⑤完整的ServletConfigMapping和MyTomcat方法&#xff1a; a.ServletConfigMappin…

构建一个rust生产应用读书笔记四(实战3)

从这一节开始&#xff0c;我们将继续完善邮件订阅生产级应用&#xff0c;根据作者的选型sqlx作为数据库操作的类库&#xff0c;它有如下优点&#xff1a; 它旨在提供高效、安全且易于使用的数据库交互体验。sqlx 支持多种数据库&#xff0c;包括 PostgreSQL、MySQL 和 SQLite&…

网络安全-------防止被抓包

1.Ios应用网络安全之https 安全套接字层 (Secure Socket Layer, SSL) 是用来实现互联网安全通信的最普遍的标准。Web 应用程序使用 HTTPS&#xff08;基于 SSL 的 HTTP&#xff09;&#xff0c;HTTPS 使用数字证书来确保在服务器和客户端之间进行安全、加密的通信。在 SSL 连接…

WebSocket 与 Server-Sent Events (SSE) 的对比与应用

目录 ✨WebSocket&#xff1a;全双工通信的利器&#x1f4cc;什么是 WebSocket&#xff1f;&#x1f4cc;WebSocket 的特点&#x1f4cc;WebSocket 的优点&#x1f4cc;WebSocket 的缺点&#x1f4cc;WebSocket 的适用场景 ✨Server-Sent Events (SSE)&#xff1a;单向推送的轻…

CAD c# 生成略缩图预览

代码如下&#xff1a; using (Transaction tr currentdb.TransactionManager.StartTransaction()){//当前数据库开启事务using (Database tempdb new Database(false, true)) //创建临时数据库(两个参数&#xff1a;是否创建符号表&#xff0c;不与当前文档关联){try{Bitmap …

娱乐五子棋(附加源码)

一写在开头 上期代码主要实现瀑布流功能&#xff0c;本期就来实现五子棋小游戏&#xff0c;开发久了很多功能都是通过框架组件库来完成&#xff0c;但是如果组件满足不了开发需求&#xff0c;还需要开发人员手动封装组件&#xff0c;专门出这样一期文章&#xff0c;通过原生js实…

XMOS将在CES 2025上展出多款由边缘AI驱动的创新音效、音频、识别和处理解决方案

全球智能物联网技术领导者暨匠心独到的半导体科技企业XMOS宣布&#xff1a;该公司将再次参加2025年国际消费电子展&#xff08;CES 2025&#xff09;&#xff0c;并将在本届CES上展出一系列由人工智能&#xff08;AI&#xff09;驱动的全新空间音效、语音捕获与降噪、音视频多模…

HCIA-Access V2.5_2_2_2网络通信基础_IP编址与路由

网络层数据封装 首先IP地址封装在网络层&#xff0c;它用于标识一台网络设备&#xff0c;其中IP地址分为两个部分&#xff0c;网络地址和主机地址&#xff0c;通过我们采用点分十进制的形式进行表示。 IP地址分类 对IP地址而言&#xff0c;它细分为五类&#xff0c;A,B,C,D,E,…

我的数据仓库与数据挖掘期末大作业重置版

文章目录 我的数据仓库与数据挖掘期末大作业重置版准备工作预设定及导入相对应的库库的导入调整 Jupyter Notebook 的预设定调整 MatPlotLib 和 Pandas 的输出设置 任务 1&#xff1a;预测问题数据的保存和读取数据的分析和预处理模型的选择和构建线性回归一元多项式回归 拟合预…

CUDA C编程权威指南习题解析

文章目录 一、1.6节习题二、2.6习题三、四、五、六、 一、1.6节习题 1.参考图1-5&#xff0c;分析以下几种数据划分形式&#xff1a; &#xff08;1&#xff09;对于二维数据&#xff0c;沿x轴进行块划分 &#xff08;2&#xff09;对于二维数据&#xff0c;沿y轴进行周期划…

cocos creator 的 widget组件的使用及踩坑

以下的内容基于cocos creator 3.8版本&#xff0c;如有错误&#xff0c;恳请指出。 &#x1f449;官方文档的指引 应用&#xff1a;以上官方指引有非常清晰的使用方式&#xff0c;接下来说明一些注意事项&#xff1a; 1、与canvas搭配的使用&#xff0c;解决多分别率适配问题。…

PHP搭建环境

一、安装apache 1、获取Apache安装软件 2、双击安装即可:指定对应的路径:E:server/apache 3、选择安装模式:使用自定义模式 4、选择安装位置 二、Apache的目录结构说明 三、Httpd.exe的详细应用 1、服务器进程:运行之后才能够工作

微积分复习笔记 Calculus Volume 2 - 4.1 Basics of Differential Equations

4.1 Basics of Differential Equations - Calculus Volume 2 | OpenStax

0003.基于springboot的“共享书角”图书借还管理系统

适合初学同学练手项目&#xff0c;部署简单&#xff0c;代码简洁清晰&#xff1b; 一、系统架构 前端&#xff1a;vue| elementui| 微信小程序 后端&#xff1a;springboot | mybatis-plus 环境&#xff1a;jdk1.8 | mysql | maven 系统设计说明: 二、代码及数据库 1.管理…

python学opencv|读取图像(十二)BGR图像转HSV图像

【1】引言 前述已经学习了opencv中图像BGR相关知识&#xff0c;文章链接包括且不限于下述&#xff1a; python学opencv|读取图像&#xff08;六&#xff09;读取图像像素RGB值_opencv读取灰度图-CSDN博客 python学opencv|读取图像&#xff08;七&#xff09;抓取像素数据顺利…

音频进阶学习八——傅里叶变换的介绍

文章目录 前言一、傅里叶变换1.傅里叶变换的发展2.常见的傅里叶变换3.频域 二、欧拉公式1.实数、虚数、复数2.对虚数和复数的理解3.复平面4.复数和三角函数5.复数的运算6.欧拉公式 三、积分运算1.定积分2.不定积分3.基本的积分公式4.积分规则线性替换法分部积分法 5.定积分计算…

智能高效的IDE GoLand v2024.3全新发布——支持最新Go语言

GoLand 使 Go 代码的阅读、编写和更改变得非常容易。即时错误检测和修复建议&#xff0c;通过一步撤消快速安全重构&#xff0c;智能代码完成&#xff0c;死代码检测和文档提示帮助所有 Go 开发人员&#xff0c;从新手到经验丰富的专业人士&#xff0c;创建快速、高效、和可靠的…

SQL server学习06-查询数据表中的数据(中)

目录 一&#xff0c;聚合函数 1&#xff0c;常用聚合函数 2&#xff0c;具体使用 二&#xff0c;GROP BY子句分组 1&#xff0c;基础语法 2&#xff0c;具体使用 3&#xff0c;加上HAVING对组进行筛选 4&#xff0c;使WHERE记录查询条件 汇总查询&#xff1a;在对数…