当前位置: 首页 > 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 中连…...

Leecode刷题C++之形成目标字符串需要的最少字符串数①

执行结果:通过 执行用时和内存消耗如下&#xff1a; 代码如下&#xff1a; class Solution { public:int minValidStrings(vector<string>& words, string target) {auto prefix_function [](const string& word, const string& target) -> vector<…...

Linux应用开发————mysql数据库

数据库概述 什么是数据库(database)? 数据库是一种数据管理的管理软件&#xff0c;它的作用是为了有效管理数据&#xff0c;形成一个尽可能无几余的数据集合&#xff0c;并能提供接口&#xff0c;方便用户使用。 数据库能用来干什么? 顾名思义&#xff0c;仓库就是用来保存东…...

4_使用 HTML5 Canvas API (3) --[HTML5 API 学习之旅]

4_使用 HTML5 Canvas API (3) --[HTML5 API 学习之旅] 1.缩放 canvas 对象 在 <canvas> 中缩放对象可以通过 scale 方法来实现。这个方法会根据提供的参数对之后绘制的所有内容进行缩放。下面是两个具体的示例&#xff0c;展示如何使用 scale 方法来缩放 canvas 上的对…...

docker build次数过多,导致磁盘内存不足:ERROR: no space left on device

在使用 docker build 构建镜像时&#xff0c;Docker 会创建一个临时的构建上下文&#xff0c;生成镜像的过程中会产生多个中间层。这些文件和层会占用磁盘空间。构建完成后&#xff0c;如果你没有清理这些不再使用的中间层和临时文件&#xff0c;可能会导致磁盘空间不足。 常见…...

LDO和DC-DC的区别、DCDC和LDO主要指标

LDO和DC-DC的区别 LDO外围器件少&#xff0c;电路简单&#xff0c;成本低&#xff1b;DC-DC外围器件多&#xff0c;电路复杂&#xff0c;成本高&#xff1b; LDO负载响应快&#xff0c;输出纹波小&#xff1b;DC-DC负载响应比LDO慢&#xff0c;输出纹波大&#xff1b; LDO效…...

LeetCode hot100-81

https://leetcode.cn/problems/climbing-stairs/description/?envTypestudy-plan-v2&envIdtop-100-liked 70. 爬楼梯 已解答 简单 相关标签 相关企业 提示 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&…...

RTMP、RTSP、RTP、HLS、MPEG-DASH协议的简介,以及应用场景

​实时视频传输协议 1. RTMP&#xff08;Real Time Messaging Protocol&#xff09; 简介&#xff1a;RTMP是由Adobe公司开发的实时消息传输协议&#xff0c;主要用于流媒体数据的传输。它基于TCP传输&#xff0c;具有低延迟、高可靠性的特点。特点&#xff1a;RTMP支持多种视…...

力扣-图论-15【算法学习day.65】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向和记录学习过程&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非…...

“AI智慧数字孪生系统:开启智能新纪元

嘿&#xff0c;大家好&#xff01;今天我想和大家聊聊一个特别酷炫的话题——AI智慧数字孪生系统。这可是个新鲜玩意儿&#xff0c;可能有些朋友还不太了解&#xff0c;别急&#xff0c;我来慢慢道来。 首先&#xff0c;啥叫数字孪生呢&#xff1f;简单来说&#xff0c;就是给现…...

54、库卡机器人轴的软限位设置

步骤1&#xff1a;将用户组改为“专家”。 步骤2&#xff1a;点击“投入运行”----“售后服务”-----“软件限位开关” 步骤3&#xff1a;就可以针对每个轴修改对应的角度值&#xff0c;然后点击“保存”。...