vant4+vue3上传一个pdf文件并实现pdf的预览。使用插件pdf.js
注意下载的插件的版本"pdfjs-dist": "^2.2.228",
npm i pdfjs-dist@2.2.228
然后封装一个pdf的遮罩。因为pdf文件有多页,所以我用了swiper轮播的形式展示。因为用到移动端,手动滑动页面这样比点下一页下一页的方便多了。
直接贴代码了
PdfPreview/index.vue
<!--预览pdf文件的组件--> <template><van-overlay :show="show" @click="close()"><div class="pdf-viewer" ><van-swipe class="my-swipe" indicator-color="red" @click.stop><van-swipe-item v-for="item in pageNum" :key="item"><canvas :id="`pdf-canvas-${item}`" class="pdf-page"/></van-swipe-item><template #indicator="{ active, total }"><div class="custom-indicator">{{ active + 1 }}/{{ total }}</div></template></van-swipe><van-emptyv-if="loadError"image="error"description="PDF加载出错了..."/></div><van-icon name="close" color="#fff" size="0.3rem"/></van-overlay></template><script setup lang="tsx"> import {ref, nextTick, watch} from 'vue'; import {closeToast, showLoadingToast, showSuccessToast} from "vant";// 引入pdf预览插件相关的参数,注意这块开始试了很多网上方法都不好用 import * as pdfjs from 'pdfjs-dist'; import pdfjsWorker from 'pdfjs-dist/build/pdf.worker?url'; // 设置 worker 路径 pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;const show = ref(true); // html部分涉及的参数 const loadError = ref(false); const detail = ref({}); let pdfDoc = null; // 一定不能使用响应式的数据,会报错Cannot read from private field---pdf.js const pageNum = ref(0);const props = defineProps({pdfUrl: {type: String,default: ""}, }) const emit= defineEmits(['close'])watch(() => props.pdfUrl, (newVal) => {// console.log("监听", newVal, props.pdfUrl)showLoadingToast('加载中');nextTick(() => {loadingPdf(props.pdfUrl); })}, {immediate: true,deep:true})// 防抖 debounce 函数的实现正确。 const debounce(func, wait, options = {}) {let timeout;const { leading = false, trailing = true } = options;return function(...args) {const later = () => {timeout = null;if (!leading) func.apply(this, args);};const callNow = leading && !timeout;clearTimeout(timeout);timeout = setTimeout(later, wait);if (callNow) func.apply(this, args);}; }// 使用防抖函数,300ms内只执行一次,避免多次点击立刻打开又关闭的情况 const close = debounce(() => {show.value = false;emit('close') }, 300, { leading: true, trailing: false });//加载pdf const loadingPdf = (url) => {const afterUrl = {url,httpHeaders: {token: `Bearer-${localStorage.getItem('token')}`,//微信小程序里面打开这个模块,发现请求401,报错信息是登陆访问超时,发现pdfjs加载pdf时没有携带token,于是在加载url时添加token即可},};const loadingTask = pdfjs.getDocument(afterUrl);loadingTask.promise.then((pdf) => {pdfDoc = pdf;pageNum.value = pdf.numPages; nextTick(() => {renderPage();});}).catch(() => {loadError.value = true;}); }// 渲染pdf const renderPage = (num = 1) => {pdfDoc.getPage(num).then((page) => {const canvas = document.getElementById(`pdf-canvas-${num}`); if(!canvas){return}const ctx = canvas.getContext('2d');const scale = 1.5;const viewport = page.getViewport({scale});// 画布大小,默认值是width:300px,height:150pxcanvas.height = viewport.height;canvas.width = viewport.width;// 画布的dom大小, 设置移动端,宽度设置铺满整个屏幕const {clientWidth} = document.body;// 减去2rem使用因为我的页面左右加了paddingcanvas.style.width = `calc(${clientWidth}px - 2rem)`;// 根据pdf每页的宽高比例设置canvas的高度canvas.style.height = `${clientWidth * (viewport.height / viewport.width)}px`;canvas.height = viewport.height;canvas.width = viewport.width;page.render({canvasContext: ctx,viewport,});//隐藏渲染所有的页面if (num < pageNum.value) {renderPage(num + 1);} else {closeToast();}}); }</script><style scoped> .pdf-viewer{display: flex;justify-content: center;align-items: center;height:100vh;width:100vw;text-align: center; } .custom-indicator {position: absolute;left: 50%;bottom: 15px;transform: translateX(-50%);padding: 2px 5px;font-size: 18px;color: #fff;background: rgba(0, 0, 0, 0.1); } </style>
上传的页面先按照这个地址这篇文章写好。稍微改动一下就可以了vant4+vue3封装一个上传公共组件.有上传和删除访问接口的过程。限制上传的格式和上传文件大小-CSDN博客
然后给组件添加一个点击预览的事件 。并把上面写好的预览组件引入
import PdfPreview from "@/components/PdfPreview/index.vue";// 点击预览文件 const showPreview=(file)=>{if(file.absoluteUrl.endsWith('.pdf')){pdfUrl.value=file.absoluteUrl;preview.value=true;} }
遇到的问题:
如果报错Uncaught (in promise) TypeError: Cannot read properties of null (reading 'getContext')
可能是canvas要找的那个id在页面还没有渲染出来。所以我用的nextTick,还在获取canvas后面判断了一下找到了再继续 ,注意上面棕色加粗的地方。
如果报错vue-router.mjs:3518SyntaxError: The requested module '/node_modules/.vite/deps/pdfjs-dist_build_pdf__worker__entry.js?v=8ae4d11f' does not provide an export named 'default'
检查一下你引入插件的地方。如果是
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry';这样写的就是错的
改成
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker?url';
问题:如果你点击第一次弹窗展示了,但是再点击就没有弹出。
原因是预览的组件渲染是监听的pdf的url的地址。如果你第一个打开没有把组件销毁。那么再次显示的时候没有走监听。就不会显示。所以要在每次关闭弹窗是组件也销毁。这就是上面我要在子组件中用@close给组件通知让他不显示也就是销毁子组件的原因。
问题:无意间双击了文件导致遮罩马上显示又隐藏。页面效果就是黑色遮罩闪了一下。
可以使用防抖的方式。延迟关闭。参考上面紫色的关闭函数
相关文章:
vant4+vue3上传一个pdf文件并实现pdf的预览。使用插件pdf.js
注意下载的插件的版本"pdfjs-dist": "^2.2.228", npm i pdfjs-dist2.2.228 然后封装一个pdf的遮罩。因为pdf文件有多页,所以我用了swiper轮播的形式展示。因为用到移动端,手动滑动页面这样比点下一页下一页的方便多了。 直接贴代码…...
JS | 函数柯里化
函数柯里化(Currying):将一个接收多个参数函数,转换为一系列只接受一个参数的函数的过程。即 逐个接收参数。 例子: 普通函数: function add(a, b, c) {return a b c; } add(1, 2, 3); // 输出 6柯里化…...
软件工程基础之设计模式
目录 单例模式(Singleton Pattern)工厂方法模式(Factory Method Pattern)抽象工厂模式(Abstract Factory Pattern)原型模式(Prototype Pattern)适配器模式(Adapter Pattern)单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。应用场景:…...
2025 数字中国创新大赛数字安全赛道数据安全产业积分争夺赛初赛-东部赛区WriteUp
2025 数字中国创新大赛数字安全赛道数据安全产业积分争夺赛初赛-东部赛区WriteUp 数据安全:ez_upload(60分): 模型安全:数据分析:溯源与取证:1-1:1-2: 数据社工:2-2:2-3:2-4: 数据跨境ÿ…...
2025 年网络安全终极指南
我们生活在一个科技已成为日常生活不可分割的一部分的时代。对数字世界的依赖性日益增强的也带来了更大的网络风险。 网络安全并不是IT专家的专属特权,而是所有用户的共同责任。通过简单的行动,我们可以保护我们的数据、隐私和财务,降低成为…...
1.6-抓包技术(Burp Suite\Yakit抓包\Web、APP、小程序)
1.6-抓包技术(Burp Suite\Yakit抓包\Web、APP、小程序) 如果要使用抓包软件,基本上第一步都是要安装证书的。原因如下: 客户端(浏览器或应用)会检测到证书不受信任,并弹出 证书错误࿰…...
图解力扣回溯及剪枝问题的模板应用
文章目录 选哪个的问题17. 电话号码的字母组合题目描述解题代码图解复杂度 选不选的问题78. 子集题目描述解题代码图解复杂度 两相转化77. 组合题目描述解题代码法一:按选哪个的思路法二:按选不选的思路 图解选哪个:选不选 复杂度 选哪个的问…...
Elasticsearch 8.X 如何利用嵌入向量提升搜索能力?
众所周知,Elasticsearch 是一个非常流行的搜索引擎,因为它速度快、扩展性强,尤其擅长全文搜索。 近两年,向量嵌入(Vector Embedding)技术的引入,让 Elasticsearch 在处理高级搜索场景时变得更强…...
MySQL体系架构(一)
1.1.MySQL的分支与变种 MySQL变种有好几个,主要有三个久经考验的主流变种:Percona Server,MariaDB和 Drizzle。它们都有活跃的用户社区和一些商业支持,均由独立的服务供应商支持。同时还有几个优秀的开源关系数据库,值得我们了解一下。 1.1.1.Drizzle Drizzle是真正的M…...
【Docker项目实战】使用Docker部署ToDoList任务管理工具
【Docker项目实战】使用Docker部署ToDoList任务管理工具 一、ToDoList介绍1.1 ToDoList简介1.2 ToDoList主要特点二、本次实践规划2.1 本地环境规划2.2 本次实践介绍三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本四、下载ToDoList镜像…...
深度强化学习基础 0:通用学习方法
过去自己学习深度强化学习的痛点: 只能看到各种术语、数学公式勉强看懂,没有建立清晰且准确关联 多变量交互关系浮于表面,有时候连环境、代理控制的变量都混淆 模型种类繁多,概念繁杂难整合、对比或复用,无框架分析所…...
Traefik应用:配置容器多个网络时无法访问问题
Traefik应用:配置容器多个网络时无法访问问题 介绍解决方法问题原因: **容器多网络归属导致 Traefik 无法正确发现路由规则**。解决方案方法 1:将应用容器 **仅连接** 到 traefik-public 网络方法 2:显式指定 Traefik 监听的网络 …...
虚幻5的C++调试踩坑
本地调试VS附加调试 踩坑1 预编译版本的UE5没有符号文件,无法调试源码 官方代码调试所需要的符号文件bdp需要下载导入。我安装的5.5.4是预编译版本,并非ue5源码。所以不含bdp文件。需要调试官方代码则需要通过EPIC中下载安装。右键UE版本,打…...
react 中将生成二维码保存到相册
需求:生成二维码,能保存到相册 框架用的 react 所以直接 qrcode.react 插件,然后直接用插件生成二维码,这里一定要写 renderAs{‘svg’} 属性,否则会报错,这里为什么会报错??&#…...
通信协议详解(十):PSI5 —— 汽车安全传感器的“抗干扰狙击手”
一、PSI5是什么? 一句话秒懂 PSI5就像传感器界的“防弹信使”:在汽车安全系统(如气囊)中,用两根线同时完成供电数据传输,即便车祸时线路受损,仍能确保关键信号准确送达! 基础概念…...
C语言【模仿strcpy】
题目 模仿strcpy 思路(注意事项) 注意需要在复制的字符串结尾加\0表示字符串的终止 纯代码 #include<stdio.h>void cpy(const char *a, char *b){int i 0;while (a[i] ! \0){b[i] a[i];i ;}b[i] \0; } int main(){char a[] "HELLO&quo…...
从零开始学Python游戏编程18-函数3
《从零开始学Python游戏编程17-函数2》中,通过代码重构的方式将游戏的主要代码写入到自定义函数runGame()中。对于runGame()中的代码,可以继续对其进行重构,以达到简化代码结构的目的。 1 自定义函数askPlayer() 1.1 函数作用 自定义函数a…...
Spring事务传播机制
Spring 事务传播机制定义了在多个事务方法相互调用时,事务如何在这些方法间传播。它决定了一个事务方法调用另一个事务方法时,新的事务是如何开启、是否要加入已有的事务等情况。Spring 提供了 7 种事务传播行为,下面是详细介绍。 解释说明&…...
不同PHP框架之间的兼容性问题及应对策略!
在PHP开发领域,Laravel、Symfony、Yii、ThinkPHP、亿坊PHP等框架因其高效性和便捷性广受开发者青睐。但当项目需要跨框架协作或迁移时,兼容性问题直击要害。本文将从实际案例出发,剖析不同PHP框架间常见的兼容性痛点,并为大家提供…...
Qt 子项目依赖管理:从原理到实践的最佳分析:depends还是 CONFIG += ordered
1. 问题背景 在Qt项目开发中,当一个工程包含多个子项目(如库、插件、测试模块)时,如何正确管理它们的构建顺序和依赖关系? 如: 在开发一个包含核心库(core)、GUI模块(g…...
大数据专业学习路线
大数据专业学习路线 目录 基础知识核心技术进阶技能实战项目职业发展学习资源学习计划常见问题 1. 基础知识 1.1 编程语言 Python:大数据分析的基础语言 基础语法和数据类型函数和模块面向对象编程文件操作和异常处理常用库:NumPy, Pandas, Matplot…...
点云从入门到精通技术详解100篇-基于点云的三维多目标追踪与目标检测
目录 知识储备 基于Python和Open3D库实现的三维点云多目标检测与跟踪 技术要点解析 : 运行环境配置: 扩展改进建议 : 前言 三维多目标追踪技术 点云目标检测算法 2 二维多目标追踪框架及三维点云目标检测 2.1 二维多目标追踪框架 2.1.1 Deep SORT总体架构 2.1…...
dubbo配置中心
配置中心 简介 配置中心(config-center)在dubbo中可承担两类职责: 外部化配置:启动配置的集中式存储。流量治理规则存储。 Dubbo动态配置中心定义了两个不同层次的隔离选项,分别是namespace和group。 namespace&a…...
Java常用工具算法-5--哈希算法、加密算法、签名算法关系梳理
1、哈希算法 数学本质:将任意长度输入(明文)映射为固定长度输出(哈希值,也称摘要)。主要特点: 不可逆性:无法通过哈希值反推原始输入。雪崩效应:输入的微小变化导致哈希…...
python之安装PaddlePaddle和PaddleX解析pdf表格
目录标题 飞桨PaddlePaddle本地安装教程1-1. 基于 Docker 安装飞桨1-2. 基于 pip 安装飞桨2. 我两个环境 都选择的是pip 安装10. 如果报错10. 离线安装 飞桨PaddlePaddle本地安装教程 源码下载:https://github.com/PaddlePaddle/PaddleX/blob/release/3.0-beta1/do…...
【11408学习记录】英语语法核心突破:揭秘表语从句结构与通知写作实战技巧
表语从句与通知写作 英语语法总结——主从复合句表语从句语句结构系动词表语从句的位置 写作通知写作第二段第三段落款 每日一句词汇第一步:找谓语第二步:断句第三步:简化第一句第二句第三句第四句第五句 英语 语法总结——主从复合句 表语…...
React Native 0.79发布 - 更快的工具及更多改进
React Native 0.79版本发布了。 此版本在多个方面进行了性能改进,并修复了一些漏洞。首先,得益于延迟哈希技术,Metro的启动速度变快了,并且对包导出提供了稳定支持。由于JS包压缩方式的改变等原因,Android的启动时间也…...
封装红黑树实现map和set
前言: 之前我们学习了set与map容器的如何使用,红黑树的实现。接下来我们来看看如何通过封装红黑树,实现我们自己的set与map 相关文章:oi!让我来给你唠唠咋实现红黑树☝️-CSDN博客 超详细介绍map&…...
解码AI大脑:Claude的思维显微镜与语言炼金术
(前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站)。 一、多语言思维实验:Claude的“概念空间”如何运转? 跨语言谜题:反义词的…...
中科岩创基坑自动化监测解决方案
1.行业现状 城市基坑开挖具有施工风险高、施工难度大等特点。由于地下土体性质、荷载条件、施工环境的复杂性,单根据地质勘察资料和室内土工试验参数来确定设计和施工方案,往往含有许多不确定因素,对在施工过程中引发的土体性状、环境、邻近建…...
