预览 PDF 文档

news2024/11/23 18:47:05

引言

在现代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>');

      // 确保新窗口的内容加载完成后再释放 URL
      tempWindow.onload = function () {
        window.URL.revokeObjectURL(url);
      };
    },

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

总结

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

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

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蚁剑的介绍和使用

蚁剑介绍 蚁剑&#xff08;AntSword&#xff09;是一个开源的跨平台网站管理工具&#xff0c;主要用于渗透测试和安全研究。它提供了一个图形化界面&#xff0c;方便用户管理和操作被攻陷的网站。 安装教程&#xff1a; github官网&#xff1a;https://github.com/AntSwordPro…

AppInventor2能否用网络摄像头画面作为屏幕的背景?

// 视频是否可以作为背景&#xff1f; // 有会员提问&#xff1a;能否用网络摄像头的实时画面作为屏幕的背景&#xff1f;就跟这个一样背景全覆盖&#xff1a; 摄像头画面是一个在线的网站链接视频流。 // 原先思路 // 1、目前原生组件无法直接实现这个功能&#xff0c;屏幕…

DBeaver如何查看ER图

前言 我们在使用DBeaver时&#xff0c;有时候需要查看某张表的ER图&#xff0c;这能帮助我们快速看到表的结构&#xff0c;那么&#xff0c;我们应该如何在DBeaver里面查看ER图呢&#xff1f; 如何查看 首先&#xff0c;我们点击下我们要查看的某张表&#xff0c;鼠标右击一…

pytest高版本兼容test_data[“log“] = _handle_ansi(“\n“.join(logs))错误

一、问题现象&#xff1a; 执行seleniumpytest结束时报: INTERNALERROR> File "D:\workspace\pytestframe\.venv\Lib\site-packages\pytest_html\report_data.py", line 141, in add_test INTERNALERROR> test_data["log"] _handle_ansi(&q…

mysql8.0.32升级到8.0.40

上篇8.0.32库的准备&#xff1a;mysql: error while loading shared libraries: libncurses.so.5: cannot open shared object file: No suc-CSDN博客 此篇测试升级到8.0.40 MySQL :: Download MySQL Community Server rootjyc:~# mysql -u root -pabcd1234 mysql: [Warning]…

【Spring】Spring 核心和设计思想

Spring 核心和设计思想 1.什么是 Spring1.1 传统程序开发1.2 控制反转程序开发 2.理解 Spring IoC 1.什么是 Spring 我们通常所说的 Spring 指的是 Spring Framework&#xff08;Spring 框架&#xff09;&#xff0c;它是⼀个开源框架&#xff0c;有着活跃而庞大的社区&#x…

白盒测试基本概念(学习笔记)

1.1白盒测试基本概念 测试工作中我们经常遇到的两种测试&#xff0c;就是白盒测试和黑盒测试。基本概念区分如下&#xff1a; 软件的白盒测试是对软件的过程性细节做细致的检查。这一方法是把测试对象看作一个打开的盒子&#xff0c;它允许测试人员利用程序内部的逻辑结构及有…

Mybatis使用和原理

Mybatis使用和原理 1、ORM架构2、Spring整合MyBatis使用2.1 添加maven依赖2.2 配置数据源2.3 创建实体类2.4 创建 MyBatis Mapper2.4.1 使用MyBatis注解2.4.2 使用XML方式 2.5 Service 层 3、Spring整合Hibernate使用3.1 添加maven依赖3.2 配置数据源3.3 创建实体类3.4 创建 Re…

C++核心编程和桌面应用开发 第十七天(set和multiset容器 pair map和multimap容器)

目录 1.set和multiset容器 1.1构造和赋值 1.2交换和大小 1.3插入和删除 1.4统计和查找 1.5pair对组 1.6set和multiset的区别 1.7指定内置数据类型排序规则 1.8指定自定义数据类型排序规则 2.map和multimap容器 2.1构造和赋值 2.2交换和大小 2.3插入和删除 2.4统计…

Android中常用adb命令

目录 1.adb连接安卓模拟器 2.adb列出所有已经连接的设备 3.adb显示设备的日志信息 4.adb 电脑文件推送到安卓模拟器中 5.adb 手机传送文件到电脑 6.adb获取安卓应用的包名和Activity名 附录 1--命令 1&#xff09;adb devices 2&#xff09;adb install 路径> 3&#xff09;…

机器学习算法之回归算法

一、回归算法思维导图 二、算法概念、原理、应用场景和实例代码 1、线性回归 1.1、概念 ‌‌线性回归算法是一种统计分析方法&#xff0c;用于确定两种或两种以上变量之间的定量关系。‌ 线性回归算法通过建立线性方程来预测因变量&#xff08;y&#xff09;和一个或多个自变量…

SpringBoot项目如何设置定时任务总开关

目录 方法一&#xff1a;使用Spring Profiles 1.1 步骤1 1.2 步骤2 1.3 步骤3 1.4 步骤4 方法二&#xff1a;使用ConditionalOnProperty 2.1 步骤1 2.2 步骤2 2.3 步骤3 方法三&#xff1a; 主启动类禁用EnableScheduling 定时任务原理剖析&#xff08;选看&#xf…

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-21

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-21 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-21目录1. The Fair Language Model Paradox摘要研究背景问题与挑战如何解决创新点算法模型实验效果重要数据与结论推荐阅读指数&…

Python——实时域名通信状态监控

在互联网时代&#xff0c;网站和在线服务的可用性对于个人和企业都至关重要。域名的通信状态直接关系到服务的可达性&#xff0c;因此&#xff0c;实时监控域名的通信状态成为了一项基本需求。本文将详细介绍一个使用Python编写的简单域名通信状态监控工具&#xff0c;该工具能…

vue vxeui 上传组件 vxe-upload 全局配置上传方法,显示上传进度,最完美的配置方案

Vxe UI 上传组件 vxe-upload 全局配置上传方法&#xff0c;显示上传进度&#xff0c;最完美的配置方案 正常使用上传组件 vxe-upload&#xff0c;都是在用的时候传自定义上传方法&#xff0c;然后进行处理。几个页面是没什么问题&#xff0c;当系统页面非常多的时候&#xff0…

springboot 修复 Spring Framework 特定条件下目录遍历漏洞(CVE-2024-38819)

刚解决Spring Framework 特定条件下目录遍历漏洞&#xff08;CVE-2024-38816&#xff09;没几天&#xff0c;又来一个新的&#xff0c;真是哭笑不得啊。 springboot 修复 Spring Framework 特定条件下目录遍历漏洞&#xff08;CVE-2024-38816&#xff09;https://blog.csdn.ne…

SSH登录介绍

说明&#xff1a;一般登录服务器&#xff0c;我们可以用远程连接工具&#xff0c;如XShell、Windterm等&#xff0c;或者通过公司搭建的JumpServer&#xff08;跳板机、堡垒机&#xff09;来连接。前者是点对点登录&#xff0c;输入主机、端口&#xff0c;通过SSH协议登录&…

Unity计算二维向量夹角余弦值和正弦值的优化方法参考

如果不考虑优化问题&#xff0c;计算两个向量的余弦值或者正弦值可以直接使用类似的方法&#xff1a; [SerializeField] Vector2 v1, v2;void Start() {float valCos Mathf.Acos(Vector2.SignedAngle(v1, v2));float valSin Mathf.Asin(Vector2.SignedAngle(v1, v2)); } 但是…

理解 CSS 中的绝对定位与 Flex 布局混用

理解 CSS 中的绝对定位与 Flex 布局混用 在现代网页设计中&#xff0c;CSS 布局技术如 flex 和绝对定位被广泛使用。然而&#xff0c;这两者结合使用时&#xff0c;可能会导致一些意想不到的布局问题。本文将探讨如何正确使用绝对定位元素&#xff0c;避免它们受到 flex 布局的…

JAVA力扣每日一题:P3216. 交换后字典序最小的字符串

本题来自&#xff1a;力扣-每日一题 力扣 (LeetCode) 全球极客挚爱的技术成长平台https://leetcode.cn/ 题解&#xff1a; class Solution {public String getSmallestString(String s) {int len s.length();int[] arr new int[len];for (int i 0; i < len; i) {arr[i…