当前位置: 首页 > news >正文

UniApp 实现pdf上传和预览

一、上传

1、html

<template><button @click="takeFile">pdf上传</button>
</template>

2、JS

takeFile() {// #ifdef H5// H5端使用input方式选择文件const input = document.createElement('input');input.type = 'file';input.accept = '.pdf';input.onchange = (e) => {if (e.target.files && e.target.files[0]) {this.handleSelectedFile(e.target.files[0]);}};input.click();// #endif// #ifdef MP-WEIXIN// 微信小程序选择文件wx.chooseMessageFile({count: 1,type: 'file',extension: ['.pdf'],success: (res) => {if (res.tempFiles && res.tempFiles[0]) {this.handleSelectedFile(res.tempFiles[0]);}},fail: (err) => {console.error('选择文件失败:', err);this.showToast('选择文件失败,请重试');}});// #endif// #ifdef APP-PLUSif (plus.os.name === 'Android') {this.selectPdfAndroid();} else {this.selectPdfIOS();}// #endif},// Android端使用Intent选择PDFselectPdfAndroid() {try {const Intent = plus.android.importClass('android.content.Intent');const Activity = plus.android.runtimeMainActivity();const intent = new Intent(Intent.ACTION_GET_CONTENT);intent.setType('application/pdf');intent.addCategory(Intent.CATEGORY_OPENABLE);Activity.startActivityForResult(intent, 1001);Activity.onActivityResult = (requestCode, resultCode, data) => {if (requestCode === 1001 && resultCode === Activity.RESULT_OK && data) {const uri = data.getData();this.handleAndroidUri(uri);}};} catch (error) {console.log('Android Intent失败:', error);this.showToast('当前设备不支持文件选择');}},// 处理Android URI - 简化版本handleAndroidUri(uri) {try {const uriString = uri.toString();console.log('选择的文件URI:', uriString);// 简化处理:生成默认文件名,直接上传const timestamp = Date.now();const fileName = `document_${timestamp}.pdf`;console.log('准备上传文件:', { fileName, uriString });// 直接使用URI进行上传,不获取详细信息this.selectedFile = {path: uriString,name: fileName,size: 0 // 不获取大小,让服务器端验证};this.uploadPdf();} catch (error) {console.log('处理URI失败:', error);this.showToast('文件处理失败,请重试');}},// iOS端选择PDFselectPdfIOS() {// iOS可以使用plus.gallery,设置过滤器plus.gallery.pick((path) => {const fileName = path.split('/').pop() || 'document.pdf';if (fileName.toLowerCase().endsWith('.pdf')) {this.selectedFile = {path: path,name: fileName,size: 0};this.uploadPdf();} else {this.showToast('请选择PDF文件');}},(error) => {console.log('iOS选择失败:', error);this.showToast('文件选择失败');},{filter: 'file'});},/*** 处理选中的文件*/handleSelectedFile(file) {// 验证文件类型if (!this.isPdfFile(file)) {this.showToast('请选择PDF格式的文件');return;}// 验证文件大小 (5MB)if (file.size > 5 * 1024 * 1024) {this.showToast('文件大小不能超过5MB');return;}console.log('pdf', file)this.selectedFile = file;// this.uploadProgress = 0;this.uploadPdf();},/*** 验证是否为PDF文件*/isPdfFile(file) {// #ifdef H5return file.type === 'application/pdf' || file.name.endsWith('.pdf');// #endif// #ifdef MP-WEIXIN || APP-PLUSreturn file.name.endsWith('.pdf');// #endif},/*** 显示提示消息*/showToast(message) {uni.showToast({title: message,icon: 'none'})}

3、打包配置

  /* android打包配置 */"android" : {"permissions" : ["<uses-feature android:name=\"android.hardware.camera\"/>","<uses-feature android:name=\"android.hardware.camera.autofocus\"/>","<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>","<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>","<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>","<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>","<uses-permission android:name=\"android.permission.CALL_PHONE\"/>","<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>","<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>","<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>","<uses-permission android:name=\"android.permission.INTERNET\"/>","<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>","<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>","<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>","<uses-permission android:name=\"android.permission.READ_LOGS\"/>","<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>","<uses-permission android:name=\"android.permission.VIBRATE\"/>","<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>","<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>","<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>","<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>","<uses-permission android:name=\"android.permission.RECORD_AUDIO\" />","<uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>","<uses-permission android:name=\"android.permission.MANAGE_EXTERNAL_STORAGE\"/>","<uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\"/>"],"abiFilters" : []},/* ios打包配置 */"ios" : {"idfa" : false,"privacyDescription" : {"NSMicrophoneUsageDescription" : "用户上传视频时需使用音频信息","NSSpeechRecognitionUsageDescription" : "请允许使用您的语音识别,以便更好的体验该应用","NSPhotoLibraryUsageDescription" : "需要用与评论上传,头像上传功能","NSPhotoLibraryAddUsageDescription" : "保存图片到本地","NSFaceIDUsageDescription" : "使用面部识别进行登录","NSCameraUsageDescription" : "需要用与扫描二维码和图片拍摄","NSLocationWhenInUseUsageDescription" : "获得地理位置,为您推荐最近的好友,允许吗?","NSLocationAlwaysUsageDescription" : "需要您同意才能获得您的地理位置,允许吗?","NSLocationAlwaysAndWhenInUseUsageDescription" : "需要一直获取您的地理位置信息,允许吗?"},"dSYMs" : false},

二、预览

1、预览组件

<template><view class="container"><!-- 导航栏 --><!-- <view class="navbar"><view class="back-btn" @click="handleBack"><uni-icons type="left" size="24" color="#333"></uni-icons></view><view class="title">{{ title || 'PDF预览' }}</view><view class="right-space"></view></view> --><!-- PDF      web-view组件:- 用于加载PDF预览页面- 注意:src需要在manifest.json中配置web-view的域名白名单--><web-view :src="webviewUrl" @message="handleWebviewMessage" class="webview":webview-styles="webviewStyles"></web-view><!-- 加载提示 --><!-- <view v-if="loading" class="loading-mask"><view class="loading-container"><uni-loading type="spinner" size="24"></uni-loading><view class="loading-text">加载中...</view></view></view> --></view>
</template><script>
export default {data() {return {title: "", // PDF标题pdfUrl: "", // PDF文件地址webviewUrl: "", // web-view加载的URLloading: true, // 加载状态webviewStyles: {// width: '100%',// height: '90%'},};},onLoad(options) {// 获取页面参数this.title = options.title || "";this.pdfUrl = decodeURIComponent(options.url || "");// 验证PDF URLif (!this.pdfUrl) {uni.showToast({title: "缺少PDF文件地址",icon: "none",duration: 2000,});setTimeout(() => {this.handleBack();}, 2000);return;}// #ifdef H5window.addEventListener('message', (e) => {// console.log(e,e.data.data[0].action)this.dealMessage(e.data.data[0])})// #endif// 初始化web-view URLthis.initWebviewUrl();},methods: {/*** 初始化web-view加载的URL*/initWebviewUrl() {// 构建PDF预览页面的URL(使用hybrid中的html页面)// 注意:根据实际项目目录结构调整路径let viewerUrl = "/static/html/pdfViewer.html";// 处理不同平台的路径// #ifdef H5// 添加参数:PDF地址和标题const params = new URLSearchParams();params.append("url", this.pdfUrl);params.append("title", this.title);console.log(params);// H5平台需要完整路径viewerUrl = location.origin + viewerUrl + "?" + params.toString();// #endif// #ifndef H5// 非H5平台直接拼接参数// 添加参数:PDF地址和标题viewerUrl =viewerUrl + "?" + "url=" + this.pdfUrl + "&title=" + this.title;// #endifthis.webviewUrl = viewerUrl;},/*** 处理web-view发送的消息*/handleWebviewMessage(e) {console.log(e)this.dealMessage(e.detail.data[0][0])},dealMessage(data) {if (data.action === "back") {// 处理返回事件this.handleBack();} else if (data.action === "loaded") {// 处理PDF加载完成事件this.loading = false;} else if (data.action === "error") {// 处理PDF加载错误this.loading = false;uni.showToast({title: "PDF加载失败",icon: "none",duration: 2000,});}},/*** 处理返回按钮点击*/handleBack() {uni.navigateBack({delta: 1, // 返回的页面数,1表示返回上一级success: function () {console.log("返回上一页成功");},fail: function (error) {console.error("返回上一页失败", error);},});},},
};
</script><style lang="scss" scoped>
.container {display: flex;flex-direction: column;height: 100vh;
}.navbar {display: flex;align-items: center;height: 44px;background-color: #fff;border-bottom: 1px solid #eee;padding: 0 16px;/* #ifndef H5 */padding-top: 44px;height: 88px;/* #endif */box-sizing: border-box;
}.back-btn {width: 44px;height: 44px;display: flex;align-items: center;justify-content: center;
}.title {flex: 1;text-align: center;font-size: 17px;color: #333;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;
}.right-space {width: 44px;height: 44px;
}.webview {flex: 1;width: 100%;
}.loading-mask {position: fixed;top: 44px;left: 0;right: 0;bottom: 0;background-color: rgba(255, 255, 255, 0.8);display: flex;align-items: center;justify-content: center;z-index: 999;
}.loading-container {display: flex;flex-direction: column;align-items: center;
}.loading-text {margin-top: 12px;font-size: 14px;color: #666;
}
</style>

2、预览页面

<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="UTF-8" /><metaname="viewport"content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/><title>PDF预览</title><!-- 引入PDF.js库 --><script src="./pdf.min.js"></script><script type="text/javascript" src="./uni.webview.1.5.6.js"></script><style>* {margin: 0;padding: 0;box-sizing: border-box;}body {background-color: #f5f5f5;overflow-x: hidden;}#pdfContainer {padding: 16px;margin-top: 88px;}.pdf-page {width: 100%;margin-bottom: 16px;box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);background-color: #fff;border-radius: 4px;}.loading {position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);text-align: center;}.loading-text {margin-top: 16px;font-size: 14px;color: #333;}.error-container {position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);text-align: center;padding: 20px;}.error-text {font-size: 16px;color: #f66;margin-bottom: 20px;}.retry-btn {padding: 8px 16px;background: linear-gradient(300deg, #02c6ea 0%, #67f2b1 100%);color: white;border: none;border-radius: 20px;font-size: 14px;cursor: pointer;}.navbar {position: fixed;top: 0;left: 0;width: 100%;z-index: 99999;display: flex;width: 100%;align-items: center;background-color: #fff;border-bottom: 1px solid #eee;/* #ifndef H5 */padding-top: 44px;height: 88px;/* #endif */box-sizing: border-box;}.navbar.h5 {height: 44px;padding: 0 16px;}.back-btn {width: 44px;height: 44px;display: flex;align-items: center;justify-content: center;}.back-icon {width: 9px;height: 15px;background-image: url(./back.png);background-repeat: no-repeat;background-position: 0 0;background-size: 100% 100%;}.title {flex: 1;text-align: center;font-size: 17px;color: #333;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}.title > div {padding-right: 22px;}.right-space {width: 44px;height: 44px;}</style></head><body><div class="navbar" id="nav"><div class="back-btn" id="back"><div class="back-icon"></div></div><div class="title"><div>PDF预览</div></div></div><div id="loading" class="loading"><div class="loading-text">加载中...</div></div><div id="error" class="error-container" style="display: none"><div class="error-text">PDF加载失败</div><button class="retry-btn" id="retryBtn">重试</button></div><div id="pdfContainer"></div><script>let env = null;document.addEventListener("UniAppJSBridgeReady", function () {uni.getEnv(function (res) {env = res;console.log("当前环境:" + JSON.stringify(res));if (res.h5) {const cls = document.getElementById("nav").className;document.getElementById("nav").setAttribute("class", cls + " h5");//  console.log(cls)}});});// 向uni-app发送消息function sendMessage(action, data = {}) {console.log(env);if (env.h5) {// H5环境window.parent.postMessage({data: [{ action, ...data }],},"*");} else {uni.postMessage({data: [{ action, ...data }],});}}// 获取URL参数function getUrlParams() {const params = {};const search = window.location.search.substring(1);const pairs = search.split("&");pairs.forEach((pair) => {const [key, value] = pair.split("=");if (key) {params[key] = decodeURIComponent(value || "");}});return params;}// 初始化PDF预览async function initPdfViewer() {const params = getUrlParams();let pdfUrl = params.url;if (!pdfUrl) {showError();return;}try {// 处理本地文件路径(App平台)if (pdfUrl.startsWith("_doc/") || pdfUrl.startsWith("_downloads/")) {pdfUrl = window.location.origin + pdfUrl;}console.log(pdfUrl);// 配置PDF.jsconst pdfjsLib = window["pdfjs-dist/build/pdf"];pdfjsLib.GlobalWorkerOptions.workerSrc = "./pdf.worker.min.js";// 加载PDF文档const loadingTask = pdfjsLib.getDocument(pdfUrl);const pdfDoc = await loadingTask.promise;console.log(pdfDoc);// 隐藏加载状态,通知uni-app加载完成document.getElementById("loading").style.display = "none";sendMessage("loaded");// 渲染所有页面for (let pageNum = 1; pageNum <= pdfDoc.numPages; pageNum++) {const page = await pdfDoc.getPage(pageNum);// 设置缩放比例以适应移动设备const viewport = page.getViewport({ scale: 1.2 });// 创建画布元素const canvas = document.createElement("canvas");canvas.className = "pdf-page";document.getElementById("pdfContainer").appendChild(canvas);const context = canvas.getContext("2d");canvas.height = viewport.height;canvas.width = viewport.width;// 渲染页面const renderContext = {canvasContext: context,viewport: viewport,};await page.render(renderContext).promise;}} catch (error) {console.error("PDF加载失败:", error);showError();sendMessage("error", { message: error.message });}}// 显示错误状态function showError() {document.getElementById("loading").style.display = "none";document.getElementById("error").style.display = "block";}// 重试按钮事件document.getElementById("retryBtn").addEventListener("click", () => {document.getElementById("error").style.display = "none";document.getElementById("loading").style.display = "block";document.getElementById("pdfContainer").innerHTML = "";initPdfViewer();});// 页面加载完成后初始化window.addEventListener("DOMContentLoaded", initPdfViewer);window.onload = () => {document.getElementById("back").addEventListener("click", () => {console.log("back");sendMessage("back");});};// 监听页面返回事件(Android物理返回键)document.addEventListener("backbutton",() => {sendMessage("back");},false);</script></body>
</html>

http://www.dtcms.com/a/338915.html

相关文章:

  • 大模型级部署:从本地轻量化到云原生方案
  • 基于单片机智能密码锁/密码箱/门锁/门禁系统
  • Python爬虫实战:研究ICP-Checker,构建ICP 备案信息自动查询系统
  • PiscCode迅速集成YOLO-Pose 实现姿态关键点轨迹跟踪应用
  • 从繁琐到优雅:Java Lambda 表达式全解析与实战指南
  • 第1章 React组件开发基础
  • JxBrowser 8.10.0 版本发布啦!
  • iOS App 混淆工具实战,教育培训类 App 的安全保护方案
  • CTFshow系列——命令执行web34-37
  • RK3128增加usb调试模式,开放adb和root权限
  • leetcode 有效的括号
  • 西游记23:三藏不忘本,四圣试禅心;八戒挑行李;分工明确;
  • Java试题-选择题(11)
  • 从闲置到珍宝:旧物回收小程序系统重塑物品价值
  • dockerfile文件中crlf与lf换行符问题
  • 记录Webapi Excel 导出
  • 电影购票+票房预测系统 - 后端项目介绍(附源码)
  • Android Studio常用知识总结
  • HP Pavilion G6 笔记本使用ventoy启动安装Ubuntu 22.04 桌面版
  • Redission是什么
  • 低延迟、跨平台与可控性:直播SDK的模块化价值解析
  • 探访隐形冠军|安贝斯携手武汉科创协会x深钣协“湖北行”,溯源南海光电的创新密码
  • Qt个人通讯录项目开发教程 - 从零开始构建联系人管理系统
  • 【运维进阶】Ansible 角色管理
  • 【自动化运维神器Ansible】Playbook调用Role详解:从入门到精通
  • 数字孪生 :提高制造生产力的智能方法
  • 红日靶场03
  • 【Qt】 数据库连接池
  • B站 韩顺平 笔记 (Day 23)
  • LG P3710 方方方的数据结构 Solution