预览 PDF 文档

引言

在现代Web应用中,文件预览功能是非常常见的需求之一。特别是在企业级应用中,用户经常需要查看各种类型的文件,如 PDF、Word、Excel 等。本文将详细介绍如何在Vue项目中实现 PDF 文档的预览功能。

实现原理

后端API

后端需要提供一个API接口,用于获取文件的二进制数据。这个接口通常会根据文件名或文件ID来返回文件内容。

前端处理

前端通过调用后端 API 获取文件的二进制数据,并将其转换为 Blob 对象。然后使用window.URL.createObjectURL 方法生成一个临时的 URL,最后通过 window.open 方法在新窗口中打开这个 URL,从而实现文件预览。

代码示例

node 服务端代码

const express = require('express');
const multer = require('multer');
const fs = require('fs');
const path = require('path');const app = express();
// 定义文件夹路径
const mergedDir = path.join(__dirname, 'merged');// 文件下载接口
app.get('/download', (req, res) => {const { fileName } = req.query;const filePath = path.join(mergedDir, fileName);fs.access(filePath, fs.constants.F_OK, (err) => {if (err) {return res.status(404).json({ error: '文件不存在' });}const stats = fs.statSync(filePath);if (stats.isFile()) {const contentType = getContentType(fileName);res.setHeader('Content-Type', contentType);// 对 fileName 进行编码const encodedFileName = encodeURIComponent(fileName);res.setHeader('Content-Disposition', `attachment; filename=${encodedFileName}`);fs.createReadStream(filePath).pipe(res);} else {res.status(400).json({ error: '不是一个文件' });}});
});// 获取文件的 MIME 类型
function getContentType(fileName) {const ext = path.extname(fileName).toLowerCase();switch (ext) {case '.js':return 'application/javascript';case '.json':return 'application/json';case '.html':return 'text/html';case '.css':return 'text/css';case '.txt':return 'text/plain';case '.png':return 'image/png';case '.jpg':case '.jpeg':return 'image/jpeg';case '.gif':return 'image/gif';case '.pdf':return 'application/pdf';case '.doc':return 'application/msword';case '.docx':return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';case '.ppt':return 'application/vnd.ms-powerpoint';case '.pptx':return 'application/vnd.openxmlformats-officedocument.presentationml.presentation';case '.xlsx':return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';default:return 'application/octet-stream';}
}
// 启动服务器
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {console.log(`Server is running on port ${PORT}`);
});

前端代码实现

接口 API

import request from "@/utils/request";// 获取文件列表
export function getFilesList() {return request({url: "/getFilesList",method: "get",});
}// 文件预览
export function previewFile(fileName) {return request({url: `/download?fileName=${fileName}`,method: "get",responseType: "blob",});
}

页面代码

<template><div class="table"><el-table :data="tableData" header-align="center" border style="width: 100%"><el-table-column align="center" type="index" width="60" label="序号"></el-table-column><el-table-column align="center" prop="fileName" label="文件名" /><el-table-column align="center" prop="upTime" label="上传日期" width="200" /><el-table-column align="center" fixed="right" label="操作" width="120"><template slot-scope="scope"><el-button @click="handleClick(scope.row)" type="text">预览</el-button></template></el-table-column></el-table></div>
</template><script>
import { previewFile } from "@/api/file";
import { timeStampToString } from "@/utils/utils";
import { getFilesList } from "@/api/file";export default {name: "fileTable",data() {return {tableData: [],}},created() {this.getFileName();},methods: {// 获取文件列表async getFileName() {const { code, data: resData } = await getFilesList();console.log('code, data::: ', code, resData);if (code === 200) {resData.forEach(item => {item.upTime = timeStampToString(item.upTime);});this.tableData = resData;}},handleBlob(blob, filename) {console.log('blob::: ', blob,filename);let url = window.URL.createObjectURL(blob);var tempwindow = window.open("_blank");if (tempwindow) {tempwindow.location = url;}},// 文件预览async handleClick(row) {try {const response = await previewFile(row.fileName)console.log('response::: ', response);this.handleBlob(response, row.fileName)} catch (err) {console.error('Failed to preview file', err);}},}
}
</script>

实现效果
在这里插入图片描述

设置网页标题为文件名

 handleBlob(blob, filename) {console.log('blob::: ', blob, filename);let url = window.URL.createObjectURL(blob);// 创建一个新窗口let tempWindow = window.open("", "_blank");// 设置新窗口的标题为文件名tempWindow.document.title = filename;// 在新窗口中嵌入一个 <iframe> 来预览 PDF 文件tempWindow.document.write('<html><head><title>' + filename + '</title></head><body>');tempWindow.document.write('<iframe src="' + url + '" style="width:100%;height:100%;border:none;"></iframe>');tempWindow.document.write('</body></html>');// 确保新窗口的内容加载完成后再释放 URLtempWindow.onload = function () {window.URL.revokeObjectURL(url);};},

修改后的效果
在这里插入图片描述

总结

本文详细介绍了如何在Vue项目中实现PDF文档的预览功能。通过前后端的协同工作,我们实现了从文件的存储、获取到预览的完整流程。具体来说:

  • 后端API:提供了文件下载接口,根据文件名或文件ID返回文件的二进制数据,并设置了正确的MIME类型。

  • 前端处理:通过调用后端API获取文件的二进制数据,将其转换为 Blob 对象,并生成一个临时的 URL。然后在新窗口中打开这个 URL,实现文件预览。

  • 优化体验:为了提升用户体验,我们进一步优化了预览功能,通过在新窗口中嵌入 <iframe> 并设置网页标题为文件名,使得预览界面更加友好和直观。

通过本文的介绍,读者可以轻松地在自己的Vue项目中实现类似的功能,提升应用的用户体验。希望本文对大家有所帮助。

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

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

相关文章

GIT使用list

清空当前commit区 方法 1&#xff1a;软重置到初始状态 如果希望保留文件内容&#xff0c;但清空所有 commit 历史&#xff0c;可以使用以下命令&#xff1a; git reset --soft $(git rev-list --max-parents0 HEAD)解释&#xff1a; --soft 表示重置 commit 历史&#xff…

uniapp的IOS证书申请(测试和正式环境)及UDID配置流程

1.说明 本教程只提供uniapp在ios端的证书文件申请&#xff08;包含正式环境和开发环境&#xff09;、UDID配置说明&#xff0c;请勿用文档中的账号和其他隐私数据进行测试&#xff0c;请勿侵权&#xff01; 2.申请前准备 证书生成网站&#xff1a;苹果应用上传、解析&#x…

【AscendC算子开发】笔记3 矩阵计算及高级开发技巧

pytorch调用算子 矩阵计算 为什么上图提供了两种矩阵结果访问方式&#xff1f; 如果只需要结果&#xff0c;那么拿注释的一行代码就可以得到结果&#xff0c;如果之后还有其他的操作&#xff0c;可以计算一小块就用起来&#xff0c;那么需要使用上述操作&#xff0c;可以形成流…

Unity Newtonsoft.Json 大对象序列化失败

Unity Newtonsoft.Json 大对象序列化失败 &#x1f4a3;崩溃了没&#xff1f;&#x1f600;替代方案 &#x1f4a3;崩溃了没&#xff1f; Newtonsoft.Json.JsonTextWriter:WriteValueInternal(string,Newtonsoft.Json.JsonToken) InvalidCastException: Specified cast is not…

Kafka认证时Successfully logged in真的认证成功了?

背景 某个应用需要配置 Kafka 集群信息&#xff0c;且需要在验证集群是否可达。基本实现思路是创建一个生产者对象&#xff0c;然后发送一条测试数据&#xff0c;调用 Producer 的 send 方法发送消息后&#xff0c;再调用 get() 方法&#xff0c;即同步发送消息&#xff0c;测…

SpringBoot后端开发常用工具详细介绍——flyway数据库版本控制工具

文章目录 什么是flyway简介为什么要使用flyway 流程介绍整合springboot添加pom文件配置flyway向resource/db/migration添加sql文件 注意事项1. 迁移报错2. 迁移顺序 参考 什么是flyway 简介 为什么要使用flyway 我们在开发时往往会有这样一种情况&#xff1a; 进行软件开发…

【Linux系统编程】线程深入运用

目录 一&#xff0c;C线程与系统线程 二&#xff0c;分离线程 三&#xff0c;线程结构 四&#xff0c;__thread关键字 五&#xff0c;Linux线程互斥 1&#xff0c;线程互斥相关的背景概念 2&#xff0c;互斥锁 3&#xff0c;死锁 4&#xff0c;互斥锁的弊端 六&#…

2024年10月25日练习(双指针算法)

一.283. 移动零 - 力扣&#xff08;LeetCode&#xff09; 1.题目描述&#xff1a; 这里题目要求了说必须在不复制数组的情况下对数组进行原地操作&#xff0c;所以说不能来用暴力的解法来 实现。 2.算法原理&#xff1a; 这个题目就是经典的数组划分&#xff0c;数组分块问题…

react-signature-canvas 实现画笔与橡皮擦功能

react-signature-canvas git 地址 代码示例 import React, { Component } from react import { createRoot } from react-dom/clientimport SignaturePad from ../../src/index.tsximport * as styles from ./styles.module.cssclass App extends Component {state { trimmed…

NLTK无法下载?

以下内容仅为当前认识&#xff0c;可能有不足之处&#xff0c;欢迎讨论&#xff01; 文章目录 nltk无法下载怎么办&#xff1f;什么是NLTK&#xff1f;为什么要用NLTK&#xff1f;如何下载&#xff1f; nltk无法下载怎么办&#xff1f; 什么是NLTK&#xff1f; NLTK是学习自然…

【Qt】窗口——Qt窗口的概念、常用的窗口函数、菜单栏、工具栏、状态栏、浮动窗口、对话框

文章目录 Qt窗口Qt窗口的概念菜单栏工具栏状态栏浮动窗口对话框 Qt 窗口 Qt窗口的概念 QMainWindow 类概述&#xff1a; QMainWindow 是一个为用户提供主窗口程序的类&#xff0c;它继承自 QWidget 类&#xff0c;并且提供了一个预定义的布局。 菜单栏 菜单栏常用属性&#xf…

紫光同创——盘古 50KN 网口板

本原创文章由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注明出处&#xff08;www.meyesemi.com) 一、开发系统介绍 盘古 50KN 网口板开发板&#xff08;MES50H-Ethernet&#xff09;采用了核心板扩展板的结 构&#…

---synchronized 关键字---

在多线程编程中&#xff0c;由于代码的并发执行&#xff0c;导致了不同的线程在修改相同的变量会导致变量的值错误 比如 变量 c 2&#xff0c;这里有线程A 和 B一起使用 c变量并对他加1&#xff0c;这时就会有多中情况 这里要注意的是变量c是储存在内存中的&#xff0c;而线…

【git】 git 删除了文件,如何找回

git 删除了文件&#xff0c;如何找回 使用 git revert 并不是恢复误删除文件的最佳方法&#xff0c;因为 git revert 通常用于撤销已经提交的更改&#xff08;生成一个反向提交&#xff09;。如果你误删除了文件&#xff0c;还未提交更改&#xff0c;或者已经提交但想恢复删除…

2024年9月电子学会青少年软件编程Python等级考试(三级)真题试卷

2024年9月青少年软件编程Python等级考试&#xff08;三级&#xff09;真题试卷 选择题 第 1 题 单选题 以下python表达式的值为True的是&#xff1f;&#xff08; &#xff09; A.all( ,1,2,3) B.any([]) C.bool(abc) D.divmod(6,0) 第 2 题 单选题 下列python代码的…

钉钉与金蝶云星空数据集成:提高企业付款申请单处理效率

钉钉数据集成到金蝶云星空&#xff1a;付款申请单的自动下推生成 在企业日常运营中&#xff0c;如何高效地管理和处理付款申请单是一个关键问题。为了提升这一流程的效率&#xff0c;我们采用了轻易云数据集成平台&#xff0c;将钉钉中的付款申请单数据无缝对接到金蝶云星空系…

Spring Boot助力的厨艺互动平台开发指南

2 相关技术 2.1 Spring Boot框架简介 Spring Boot是由Pivotal团队提供的全新框架&#xff0c;其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。通过这种方式&#xff0c;Sprin…

代码学习:如何阅读开源代码

如何阅读开源代码 准备 目的&#xff1a;学习代码&#xff0c;代码添加新功能、旧代码重构知识准备&#xff1a;技术基础、编程基础、文档开发环境&#xff1a;依赖环境及操作系统笔记&#xff1a;添加代码注释及重要思路记录文档 实操 阅读项目Readme.md&#xff1a;大致了…

基于边缘计算的智能门禁系统架构设计分析

案例 阅读以下关于 Web 系统架构设计的叙述&#xff0c;回答问题1至问题3。 【说明】 某公司拟开发一套基于边缘计算的智能门禁系统&#xff0c;用于如园区、新零售、工业现场等存在来访被访业务的场景。来访者在来访前&#xff0c;可以通过线上提前预约的方式将自己的个人信息…

软考:CORBA架构

CORBA过时了吗 CORBA指南 个人小结&#xff1a; IPC&#xff0c;进程间通信&#xff0c;Socket应用在不同机器之间的通信 RPC是一种技术思想而非一种规范 但站在八九十年代的当口&#xff0c;简单来说&#xff0c;就是我在本地调用了一个函数&#xff0c;或者对象的方法&…