uniapp实现在线pdf预览以及下载

uniapp实现在线pdf预览以及下载

在线预览

遇到的问题

后端返回一个url 地址,我需要将在在页面中渲染出来。因为在浏览器栏上我输入url 地址就可以直接预览pdf文件,因此直接的想法是通过web-view组件直接渲染。有什么问题呢?在h5端能够正常渲染出pdf文件,但是在app端却直接弹出是否下载的弹窗。

如何解决?

利用pdfjs这个库结合html页面以及url将pdf的实际地址传给html页面

html 复制代码
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            #btn {
                width: 100%;
                height: 35px;
                background-color: #10aeff;
                color: #fff;
                line-height: 35px;
                text-align: center;
            }
        </style>
        <script src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"></script>
        <script type="module" src="/static/pdfjs-4.2.67-legacy-dist/build/pdf.js"></script>
        <script type="module" src="/static/pdfjs-4.2.67-legacy-dist/build/pdf.worker.js"></script>
        <title></title>
    </head>
    <body>
    <canvas id="the-canvas" style="width:100%; height: 80vh"></canvas>
    <button id="btn">下载</button>
    <script type="module">
    var url = '替换为真实地址';
    var { pdfjsLib } = globalThis;
    pdfjsLib.GlobalWorkerOptions.workerSrc = '/static/pdfjs-4.2.67-legacy-dist/build/pdf.worker.js';

    var loadingTask = pdfjsLib.getDocument(url);
    loadingTask.promise.then(function(pdf) {
        var pageNumber = 1;
        pdf.getPage(pageNumber).then(function(page) {
            var scale = 1.5;
            var viewport = page.getViewport({scale: scale});

            var canvas = document.getElementById('the-canvas');
            var context = canvas.getContext('2d');
            canvas.height = viewport.height;
            canvas.width = viewport.width;

            var renderContext = {
              canvasContext: context,
              viewport: viewport
            };
            var renderTask = page.render(renderContext);
            renderTask.promise.then(function () {
            });
        });
    }, function (reason) {
        // PDF loading error
        console.error(reason);
    });
    </script>
  </body>
</html>

PS :这个html页面是存在服务器的

编写好以上html界面之后,在uniapp端我们使用web-view组件来渲染该html页面

vue 复制代码
<web-view :src="src" />

使用web-view所存在的问题

  • web-view组件的层级高于一切组件,会对其他组件进行覆盖(使用定位也无法解决)

    • cover-view组件会可以解决组件的覆盖问题,但是却无法进行事件处理

    vue 复制代码
    /*
    使用一下无法触发点击事件,但是能够将文字呈现与web-view的上方
    */
    <view>
    	<web-view :src="src"></web-view>
        <cover-view>
        	<cover-view @click="handleDownload">下载</cover-view>
        </cover-view>
    </view>

如何触发下载

​ 通过以上分析,我们知道了在uniapp端已经无法实现下载功能了。那么,真的没有办法了吗?有的,兄弟,有的。通过查看官方文档,我们可以知道web-view组件提供了一个事件@message用来接收html页面发来的消息,那么,我们是不是可以将下载按钮放在html页面端,通过点击事件通知app端呢?事实证明该方案完全可行。那么页面端怎么向app端发起通信呢?需要结合uni.webview.js这个库,这个库的作用是什么------他可以让我们在非vue环境下使用uni对象。那么我们可以结合这个库使用unipostMessage方法向app发起下载的指令。在app点接收这个指令

js 复制代码
const btn = document.getElementById('btn');
document.addEventListener('UniAppJSBridgeReady', () => {
     btn.addEventListener('click', () => {
        uni.postMessage({  
            data: {  
                action: 'download'
            }  
        }); 
     })
});
vue 复制代码
<script>
export default {
    methods: {
        handleMessage(event) {
            const { action } = event.detail.data[0]
            if (action && action === 'download') {
                this.handleDownload()
            }
        }
    }
}
</script>

实现下载

vue 复制代码
<script>
export default {
methods: {
    handleDownload() {
        uni.showLoading({
            title: '下载中'
        })
        plus.downloader
            .createDownload(
                this.pdfUrl,
                {
                    filename: `file://storage/emulated/0/Download/${new Date().getTime()}.pdf`
                },
                (d, status) => {
                    if (status == 200) {
                        uni.hideLoading()
                        uni.showToast({
                            title: '下载成功',
                            icon: 'none'
                        })
                        setTimeout(() => {
                            const fileSaveUrl = plus.io.convertLocalFileSystemURL(d.filename)
                            plus.runtime.openFile(fileSaveUrl)
                        }, 500)
                    } else {
                        uni.showToast({
                            title: '下载失败',
                            icon: 'error'
                        })
                    }
                }
            )
            .start()
    }
    }
}
}
</script>
相关推荐
原则猫17 分钟前
前端基础大厦
前端
陈随易1 小时前
编程语言级别的Skill市场,AI Agent 的未来形态
前端·后端·程序员
SoaringHeart2 小时前
Flutter进阶:基于 EasyRefresh 的下拉刷新封装 n_easy_refresh_mixin.dart
前端·flutter
IT_陈寒4 小时前
Vite的热更新突然不香了,排查三小时差点砸键盘
前端·人工智能·后端
子兮曰5 小时前
Agency-Agents 深度解析:400+ AI 专家的"梦之队"如何重塑开发工作流
前端·后端·vibecoding
竹林8185 小时前
用 The Graph 查询链上数据实战:从手搓 RPC 到 Subgraph,我的 NFT 项目数据加载快了 10 倍
前端·javascript
妙码生花6 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十九):点选验证码代码逐行目检
前端·后端·go
Awu12276 小时前
⚡从零开发 Agent CLI(五)实现一个可治理、可扩展的工具系统
前端·人工智能·claude
咪库咪库咪7 小时前
Vue3-生命周期
前端
莪_幻尘7 小时前
你的 AI Skill 越多越蠢?Token 上下文爆炸的求生指南
前端·ai编程