【uniapp】App平台展示pdf文件

ios

ios比较简单,可以直接使用如下代码。

js 复制代码
let url = 'xxx.com/xx.pdf'
uni.downloadFile({
          url: url,
          success: function (res) {
            var filePath = res.tempFilePath;
            uni.openDocument({
              filePath: filePath,
              success: function (res) {
                console.log('打开文档成功');
              }
            });
          }
        });

安卓

安卓如果没有可以打开的应用,将没有反应。

主流程:使用webview,内嵌pdfjs。

下载pdfjs

下载网址:https://mozilla.github.io/pdf.js/getting_started/#download
注意 :安卓的话建议下载legacy的版本,否则一些api可能有兼容问题.

常见的错误有:Promise.withResolver() is not a functionAbortSignal.any is not a functioninvalid regular expression flags等。

浏览器支持:https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions#which-browsersenvironments-are-supported

如果需要兼容更低的版本,参考更多版本支持:https://github.com/mozilla/pdf.js/releases

uniapp的web-view组件文档:https://uniapp.dcloud.net.cn/component/web-view.html#app端web-view的扩展

新建pdfPreview.vue

直接使用pdfjs提供的viewer.html

参考如下。url为http://xxx.com/xx.pdf。此处需要获取webview并设置style,否则进入页面后,会占用状态栏和导航栏。

js 复制代码
<template>
  <web-view :src="webViewUrl"></web-view>
</template>

<script>
export default {
  data() {
    return {
      pdfUrl: '', // 原始PDF地址
      webViewUrl: '', // 本地HTML页面地址
      title: '',
    };
  },
  onLoad(options) {
    this.pdfUrl = options.url;
    this.title = options.title
    this.initWebView();
    let height = 0; //定义动态的高度变量
    let statusbar = 0; // 动态状态栏高度
    uni.getSystemInfo({
      // 获取当前设备的具体信息
      success: (sysinfo) => {
        statusbar = sysinfo.statusBarHeight;
        height = sysinfo.windowHeight;

        let currentWebview = this.$scope.$getAppWebview(); //获取当前web-view
        setTimeout(function () {
          var wv = currentWebview.children()[0];
          wv.setStyle({
            //设置web-view距离顶部的距离以及自己的高度,单位为px
            top: statusbar + 44, //此处是距离顶部的高度,应该是你页面的头部
            height: height - statusbar //webview的高度
          });
        }, 200); //如页面初始化调用需要写延迟
      }
    });
  },
  methods: {
    initWebView() {
      this.webViewUrl = `/hybrid/html/local.html?title=${this.title}&pdfUrl=${encodeURIComponent(this.pdfUrl)}`;
    }
  }
};
</script>

<style scoped></style>

hybrid/html

新建local.html如下:

html 复制代码
<!DOCTYPE html>

<html>
  <head>
    <meta name="viewport"
      content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
    <title>PDF预览</title>
    <style>
      html {
        height: 100%;
        width: 100%;

        margin: 0;
        padding: 0;
      }

      body {
        margin: 0;
        padding: 0;
      }
    </style>
  </head>

  <body>
    <div id="url"></div>
    <iframe id="iframe" src="" width="100%" height="100vh" style="height: 100vh;width:100vw;border:none;"></iframe>


    <script>
      document.addEventListener("DOMContentLoaded", function() {
        const urlParams = new URLSearchParams(window.location.search);
        url = urlParams.get("pdfUrl");
        // document.getElementById('url').innerHTML = url;
        document.getElementById('iframe').src = 'pdfjs/web/viewer.html?file=' + encodeURIComponent(url)
        const title = urlParams.get("title");
        if (title) {
          document.title = title;
        }
      });
    </script>
  </body>
</html>

把下载好的pdfjs解压,放到hybrid/html下,

可以看到这里的src开头为pdfjs/web/viewer.html,也就是pdfjs写好的预览网页。

如果有报错file origin does not match viewer's,可以修改:
pdfjs\web\viewer.js 1614行-1616行:

js 复制代码
      // if (fileOrigin !== viewerOrigin) {
      //   throw new Error("file origin does not match viewer's");
      // }

pdfjs\web\viewer.mjs 22403行:

js 复制代码
if (fileOrigin === viewerOrigin || fileOrigin !== viewerOrigin) {
      return;
    }

不同的版本可能行号不太一样,搜索file origin看下出现的地方并修改就行。

不使用pdfjs提供的viewer,而是自己写

下面是一个简单的demo:(更多demo可以参考官网

html 复制代码
<!DOCTYPE html>

<html>
  <head>
    <meta
      name="viewport"
      content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"
    />
    <title>PDF预览</title>
    <style>
      html {
        height: 100%;
        width: 100%;
      }

      .flex {
        display: flex;
      }
      .justify-between {
        justify-content: space-between;
      }
      .gap-10 {
        gap: 10px;
      }
      .items-center {
        align-items: center;
      }

      #the-canvas {
        margin-top: 20px;
        border: 1px solid grey;
        direction: ltr;
      }
      #loading {
        position: absolute;
        top: 30%;
        left: calc(50% - 15px);
        width: 30px;
        height: 30px;
        border: 2px solid #eee;
        border-top-color: #007aff;
        border-radius: 50%;
        animation: spin 1s linear infinite;
      }
      @keyframes spin {
        from {
          transform: rotate(0deg);
        }
        to {
          transform: rotate(360deg);
        }
      }
    </style>
  </head>

  <body>
    <div class="flex items-center justify-between">
      <div>
        <button id="enlarge">放大</button>
        <button id="reduce">缩小</button>
      </div>
      <div class="flex items-center gap-10">
        <span
          >Page: <span id="page_num"></span> / <span id="page_count"></span
        ></span>
        <button id="prev">上一页</button>
        <button id="next">下一页</button>
      </div>
    </div>
    <div id="loading"></div>
    <div id="error" style="color:red;"></div>
    <div id="canvas-block" style="display: none">
      <canvas id="the-canvas"></canvas>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.7.107/pdf.js"></script>

    <script>
      document.addEventListener("UniAppJSBridgeReady", function () {});
      pdfjsLib.GlobalWorkerOptions.workerSrc =
        "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.7.107/pdf.worker.js";

      var url = " ",
        pdfDoc = null,
        pageNum = 1,
        pageRendering = false,
        pageNumPending = null,
        scale = 1,
        defaultScale = 1,
        isFirstRender = true,
        canvas = document.getElementById("the-canvas"),
        ctx = canvas.getContext("2d");
      // 指定工作线程脚本的路径

      function renderPage(num) {
        // 加载PDF文档
        pdfDoc.getPage(num).then(function (page) {
          if (isFirstRender) {
            const style = window.getComputedStyle(document.body);
            const contentWidth = parseFloat(style.width);
            var desiredWidth = contentWidth;
            let defaultViewport = page.getViewport({
              scale: 1,
            });
            defaultScale = desiredWidth / defaultViewport.width;
            isFirstRender = false;
          }

          let scaledViewport = page.getViewport({
            scale,
          });
          canvas.width = scaledViewport.width;
          canvas.height = scaledViewport.height;

          let renderContext = {
            canvasContext: ctx,
            viewport: scaledViewport,
          };
          let renderTask = page.render(renderContext);

          // 等待渲染完成
          renderTask.promise.then(function () {
            pageRendering = false;
            document.getElementById("loading").style.display = "none";
            document.getElementById("canvas-block").style.display = "block";
            if (pageNumPending !== null) {
              // New page rendering is pending
              renderPage(pageNumPending);
              pageNumPending = null;
            }
          }, function (reason) {
            document.getElementById("loading").style.display = "none";
            document.getElementById("error").innerHTML = document.getElementById("error").innerHTML + '\n Error: renderTask: ' + reason;
          });

          // Update page counters
          document.getElementById("page_num").textContent = num;
        }).catch(err => {
          document.getElementById("loading").style.display = "none";
          document.getElementById("error").innerHTML = document.getElementById("error").innerHTML + '\n Error: getPage: ' + err;
        });
      }

      function queueRenderPage(num) {
        if (pageRendering) {
          pageNumPending = num;
        } else {
          renderPage(num);
        }
      }

      function onPrevPage() {
        if (pageNum <= 1) {
          return;
        }
        pageNum--;
        queueRenderPage(pageNum);
      }
      document.getElementById("prev").addEventListener("click", onPrevPage);

      function onNextPage() {
        if (pageNum >= pdfDoc.numPages) {
          return;
        }
        pageNum++;
        queueRenderPage(pageNum);
      }
      document.getElementById("next").addEventListener("click", onNextPage);

      function onEnlarge() {
        if (pageRendering) {
          return;
        }
        scale += 0.1;
        queueRenderPage(pageNum);
      }
      document.getElementById("enlarge").addEventListener("click", onEnlarge);

      function onReduce() {
        if (pageRendering) {
          return;
        }
        if (scale <= defaultScale) {
          return; // 防止过度缩小
        }
        scale -= 0.1;
        queueRenderPage(pageNum);
      }
      document.getElementById("reduce").addEventListener("click", onReduce);

      document.addEventListener("DOMContentLoaded", function () {
        const urlParams = new URLSearchParams(window.location.search);
        url = urlParams.get("pdfUrl");
        const title = urlParams.get("title");
        if (title) {
          document.title = title;
        }
        // document.getElementById('url').textContent = url;
        pdfjsLib.getDocument(url).promise.then(function (pdfDoc_) {
          pdfDoc = pdfDoc_;
          document.getElementById("page_count").textContent = pdfDoc.numPages;

          // Initial/first page rendering
          renderPage(pageNum);
        }).catch(err => {
          document.getElementById("loading").style.display = "none";
          document.getElementById("error").innerHTML = document.getElementById("error").innerHTML + '\n Error: getDocument: ' + err;
        });
      });
    </script>
  </body>
</html>

其它注意事项

  1. ios 里使用 pdfjs 将无法显示,就算直接打开pdfjs给的demo也无法展示,暂不清楚原因。
    https://mozilla.github.io/pdf.js/web/viewer.html
    https://mozilla.github.io/pdf.js/legacy/web/viewer.html

有了解的大佬请评论区留言

有任何疑问可以共同交流~

相关推荐
奔跑的web.6 小时前
UniApp 路由导航守
前端·javascript·uni-app
特立独行的猫a6 小时前
主要跨端开发框架对比:Flutter、RN、KMP、Uniapp、Cordova,谁是未来主流?
flutter·uni-app·uniapp·rn·kmp·kuikly
tiantangzhixia7 小时前
Master PDF Linux 平台的 5.9.35 版本安装与自用
linux·pdf·master pdf
万物得其道者成18 小时前
UniApp 多端滑块验证码插件 zxj-slide-verify 实用指南
uni-app
蓝帆傲亦20 小时前
支付宝小程序性能暴增秘籍:UniApp项目极限优化全攻略
小程序·uni-app
开开心心就好1 天前
发票合并打印工具,多页布局设置实时预览
linux·运维·服务器·windows·pdf·harmonyos·1024程序员节
2501_916008891 天前
深入解析iOS机审4.3原理与混淆实战方法
android·java·开发语言·ios·小程序·uni-app·iphone
软件工程小施同学1 天前
区块链论文速读 CCF A--VLDB 2025 (1) 附pdf下载
pdf·区块链
QT.qtqtqtqtqt1 天前
uni-app小程序前端开发笔记(更新中)
前端·笔记·小程序·uni-app
喵喵虫2 天前
uniapp修改封装组件失败 styleIsolation
uni-app