预览pdf(url格式和blob格式)

news2025/6/9 3:02:54
<template>
    <div class="pdf-container">
        <div v-if="loading" class="loading-state"><a-spin size="large" /></div>
        <div v-else-if="error" class="loading-state">
            加载失败,请关闭弹窗重新加载!
        </div>
        <div v-else class="pdf-viewer">
            <pdf
                v-for="i in numPages"
                :key="`${pdfInstanceKey}-${i}`"
                :src="pdfInstance"
                :page="i"
                class="pdf-page"
            />
        </div>
    </div>
</template>

<script>
import pdf from 'vue-pdf';
import { debounce } from 'lodash-es';

export default {
    name: "PdfViewer",
    components: { pdf },
    props: {
        currentPdfUrl: { type: [String, Object], required: true },
        fileType: { type: Number, default: 1 }
    },
    data() {
        return {
            numPages: 0,
            pdfInstance: null,
            pdfInstanceKey: 0,
            loading: false,
            error: false,
            activeLoadingTask: null,
            currentBlobUrl: null
        };
    },
    watch: {
        currentPdfUrl: {
            immediate: true,
            deep: true,
            handler: debounce(function(newVal) {
                if (newVal) this.loadPdf(newVal);
            }, 300)
        }
    },
    methods: {
        async loadPdf(source) {
            try {
                this.loading = true;
                this.error = false;

                // 彻底清理前一个PDF
                await this.cleanupPreviousPdf();

                // 准备新的PDF源
                const pdfSource = this.fileType === 1
                    ? { url: source, withCredentials: false }
                    : this.createBlobUrl(source);

                // 创建加载任务
                this.activeLoadingTask = this.fileType === 1
                    ? pdf.createLoadingTask({
                        url: source,
                        withCredentials: false,
                        cMapUrl: '\'@/assets/cmaps/\'',
                        // 'https://fastly.jsdelivr.net/npm/pdfjs-dist@2.11.338/cmaps/',
                        cMapPacked: true
                    })
                    : pdf.createLoadingTask(this.createBlobUrl(source));
                this.pdfInstance = this.activeLoadingTask;

                // 监听加载完成
                const pdfDocument = await this.activeLoadingTask.promise;
                this.numPages = pdfDocument.numPages;

                // 成功加载后增加实例key
                this.pdfInstanceKey++;
            } catch (err) {
                console.error('PDF加载失败:', err);
                this.handleLoadError(err);
            } finally {
                this.loading = false;
            }
        },

        createBlobUrl(fileObj) {
            // 释放之前的Blob URL
            if (this.currentBlobUrl) {
                URL.revokeObjectURL(this.currentBlobUrl);
            }
            this.currentBlobUrl = URL.createObjectURL(fileObj.originFileObj);
            return this.currentBlobUrl;
        },

        async cleanupPreviousPdf() {
            // 清理加载任务
            if (this.activeLoadingTask) {
                try {
                    // 先取消可能存在的promise
                    if (this.activeLoadingTask._transport &&
                        this.activeLoadingTask._transport.destroy) {
                        this.activeLoadingTask._transport.destroy();
                    }
                    // 销毁worker
                    this.activeLoadingTask.destroy();
                } catch (e) {
                    console.warn('清理PDF worker时出错:', e);
                }
                this.activeLoadingTask = null;
            }

            // 重置状态
            this.pdfInstance = null;
            this.numPages = 0;
        },

        handleLoadError(error) {
            this.error = true;
            this.numPages = 0;
            // 特殊处理常见错误
            if (error.name === 'PasswordException') {
                console.warn('PDF需要密码');
            } else if (error.name === 'InvalidPDFException') {
                console.warn('无效的PDF文件');
            }
        },

        retryLoading() {
            this.loadPdf(this.currentPdfUrl).catch(()=>{

            });
        }
    },
    beforeDestroy() {
        this.cleanupPreviousPdf();
        if (this.currentBlobUrl) {
            URL.revokeObjectURL(this.currentBlobUrl);
        }
    }
};
</script>

<style scoped lang="less">
.pdf-container {
    width: 100%;
    //height: 100%;
    overflow: auto;
    background-color: #f0f0f0;

    .pdf-viewer {
        display: flex;
        flex-direction: column;
        align-items: center;
        .pdf-page {
            margin-bottom: 20px;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
            background-color: white;
            width: 100%;
            &:last-child {
                margin-bottom: 0;
            }
        }
    }
}
.loading-state{
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100%;
}
</style>

追更
预览pdf版本得电子发票不太行
换个接近得组件

import pdf from 'vue-pdf-signature';
this.activeLoadingTask = this.fileType === 1
? pdf.createLoadingTask({
             url: source,
             //withCredentials: false,
             cMapUrl: `${path}cmaps/`,//'https://unpkg.com/pdfjs-dist@2.0.943/cmaps/',
             cMapPacked: true
         })
         : pdf.createLoadingTask({
             url:this.createBlobUrl(source),
             cMapUrl: `${path}cmaps/`,//'https://unpkg.com/pdfjs-dist@2.0.943/cmaps/'
             cMapPacked: true
         });

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

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

相关文章

【p2p、分布式,区块链笔记 MESH】 论文阅读 Thread/OpenThread Low-Power Wireless Multihop Net

paperauthorThread/OpenThread: A Compromise in Low-Power Wireless Multihop Network Architecture for the Internet of ThingsHyung-Sin Kim, Sam Kumar, and David E. Culler 目录 引言RPL 标准设计目标与架构设计选择与特性shortcomIngs of RPL设计选择的反面影响sImulta…

moon游戏服务器-demo运行

下载地址 https://github.com/sniper00/MoonDemo redis安装 Redis-x64-3.0.504.msi 服务器配置文件 D:\gitee\moon_server_demo\serverconf.lua 貌似不修改也可以的&#xff0c;redis不要设置密码 windows编译 安装VS2022 Community 下载premake5.exe放MoonDemo\server\moon 双…

Qt学习及使用_第1部分_认识Qt---学习目的及技术准备

前言 学以致用,通过QT框架的学习,一边实践,一边探索编程的方方面面. 参考书:<Qt 6 C开发指南>(以下称"本书") 标识说明:概念用粗体倾斜.重点内容用(加粗黑体)---重点内容(红字)---重点内容(加粗红字), 本书原话内容用深蓝色标识,比较重要的内容用加粗倾…

湖北理元理律师事务所:债务咨询中的心理支持技术应用

债务危机往往伴随心理崩溃。世界卫生组织研究显示&#xff0c;长期债务压力下抑郁症发病率提升2.3倍。湖北理元理律师事务所将心理干预技术融入法律咨询&#xff0c;构建“法律方案心理支持”的双轨服务模型。 一、债务压力下的心理危机图谱 通过对服务对象的追踪发现&#x…

阿里云域名怎么绑定

阿里云服务器绑定域名全攻略&#xff1a;一步步轻松实现网站“零”障碍上线&#xff01; 域名&#xff0c;您网站在云端的“身份证”&#xff01; 在数字化浪潮中&#xff0c;拥有一个属于自己的网站或应用&#xff0c;是个人展示、企业运营不可或缺的一环。而云服务器&#x…

能上Nature封面的idea!强化学习+卡尔曼滤波

2025深度学习发论文&模型涨点之——强化学习卡尔曼滤波 强化学习&#xff08;Reinforcement Learning, RL&#xff09;与卡尔曼滤波&#xff08;Kalman Filtering, KF&#xff09;的交叉研究已成为智能控制与状态估计领域的重要前沿方向。 强化学习通过试错机制优化决策策…

Markdown基础(1.2w字)

1. Markdown基础 这次就没目录了&#xff0c;因为md格式太乱了写示例&#xff0c;展示那些都太乱了&#xff0c;导致目录很乱。 &#xff08;我是XX&#xff0c;出现了很多错误&#xff0c;有错误和我说&#xff09; 1.1 Markdown简介 Markdown是一种轻量级的标记语言&#…

LabVIEW与PLC液压泵测控系统

针对液压泵性能测试场景&#xff0c;采用LabVIEW与西门子 PLC 控制系统&#xff0c;构建高精度、高可靠性的智能测控系统。通过选用西门子 PLC、NI 数据采集卡、施耐德变频电机等&#xff0c;结合LabVIEW 强大的数据处理与界面开发能力&#xff0c;实现液压泵压力、流量、转速等…

【HarmonyOS5】UIAbility组件生命周期详解:从创建到销毁的全景解析

⭐本期内容&#xff1a;【HarmonyOS5】UIAbility组件生命周期详解&#xff1a;从创建到销毁的全景解析 &#x1f3c6;系列专栏&#xff1a;鸿蒙HarmonyOS&#xff1a;探索未来智能生态新纪元 文章目录 前言生命周期全景图详细状态解析与最佳实践&#x1f3ac; Create状态&#…

c++ 静态成员变量

Student.h头文件内容&#xff1a; #pragma once #include <string> using namespace std;class Student { public:string name;int score;static int totalScore; // 静态局部变量声明Student(string name, int score);~Student();void print() const; };Student.cpp源文…

数据分析之OLTP vs OLAP

数据处理系统主要有两种基本方法&#xff1a;一种注重数据操作(增删查改)&#xff0c;另一种注重商业智能数据分析。 这两种系统是&#xff1a; 联机事务处理&#xff08;OLTP&#xff09; 联机分析处理&#xff08;OLAP&#xff09; Power BI专为与OLAP系统兼容而构建&…

dvwa5——File Upload

LOW 在dvwa里建一个testd2.php文件&#xff0c;写入一句话木马&#xff0c;密码password antsword连接 直接上传testd2.php文件&#xff0c;上传成功 MEDIUM 查看源码&#xff0c;发现这一关只能提交jpg和png格式的文件 把testd2.php的后缀改成jpg&#xff0c;上传时用bp抓包…

【优选算法】C++滑动窗口

1、长度最小的子数组 思路&#xff1a; class Solution { public:int minSubArrayLen(int target, vector<int>& nums) {// 滑动窗口// 1.left0,right0// 2.进窗口( nums[right])// 3.判断// 出窗口// (4.更新结果)// 总和大于等于 target 的长度最小的 子数组…

关于GitHub action云编译openwrt

特别声明:此教程仅你有成功离线编译的经验后,使用下列教程更佳 不建议没有任何成功经验的人进行云编译 1、准备工作 使用GitHub云编译模板 GitHub - jxjxcw/build_openwrt: 利用Actions在线云编译openwrt固件,适合官方源码,lede,lienol和immortalwrt源码,支持X86,电…

sql入门语句-案例

Sql入门 数据库、数据表、数据的关系介绍 数据库 用于存储和管理数据的仓库 一个库中可以包含多个数据表 数据表 数据库最重要的组成部分之一 它由纵向的列和横向的行组成(类似excel表格) 可以指定列名、数据类型、约束等 一个表中可以存储多条数据 数据 想要永久化存储…

A Survey on the Memory Mechanism of Large Language Model based Agents

目录 摘要Abstract1. LLM-Based Agent的Memory1.1 基础概念1.2 用于解释Memory的例子1.3 智能体记忆的定义1.3.1 狭义定义(肯定不用这个定义)1.3.2 广义定义 1.4 记忆协助下智能体与环境的交互过程1.4.1 记忆写入1.4.2 记忆管理1.4.3 记忆读取1.4.4 总过程 2. 如何实现智能体记…

华为OD机试 - 猴子吃桃 - 二分查找(Java 2025 B卷 200分)

public class Test14 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);while (sc.hasNext()) {String[] s = sc.nextLine().split(" ");int[] arr = new int[s.length-1];int count = Integer.parseInt(s[s

【设计模式-5】设计模式的总结

说明&#xff1a;介绍完所有的设计模式&#xff0c;本文做一下总结 设计模式介绍 博主写的设计模式博客如下&#xff1a; 【设计模式-1】UML和设计原则 【设计模式-2.1】创建型——单例模式 【设计模式-2.2】创建型——简单工厂和工厂模式 【设计模式-2.3】创建型——原型…

【无人机】无人机UAV、穿越机FPV的概念介绍,机型与工具,证书与规定

【无人机】无人机UAV、穿越机FPV的概念介绍&#xff0c;机型与工具&#xff0c;证书与规定 文章目录 1、无人机的定义、概念、技术栈1.1 无人机的概念1.2 无人机技术&#xff08;飞控&#xff0c;动力&#xff0c;通信&#xff09; 2、无人机机型2.1 DJI无人机 &#xff08;航拍…

链表好题-多种实现

143. 重排链表 - 力扣&#xff08;LeetCode&#xff09; 这道题非常经典&#xff0c;很多大厂都作为面试题。 方法一&#xff1a;寻找中点翻转链表合并链表 class Solution { public:void reorderList(ListNode* head) {if (head nullptr) {return;}ListNode* mid middleNo…