【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

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

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

相关推荐
请叫我欧皇i8 小时前
保姆级教程vscode创建uniapp vue3+ts+pinia项目并实现自动导入、打包功能
ide·vscode·uni-app
海鸥两三8 小时前
Uni-App(Vue3 + TypeScript)项目结构详解 ------ 以 Lighting-UniApp 为例,提供源代码
vue.js·typescript·uni-app·1024程序员节
知识分享小能手8 小时前
uni-app 入门学习教程,从入门到精通,uni-app 企业项目实战:鲁嗑瓜子项目开发知识点(9)
前端·javascript·学习·微信小程序·小程序·uni-app·vue
知识分享小能手8 小时前
uni-app 入门学习教程,从入门到精通,uni-app中uCharts组件学习((8)
vue.js·学习·ui·微信小程序·小程序·uni-app·echarts
社会底层无业大学生10 小时前
uniapp微信小程序简单表格展示
微信小程序·小程序·uni-app·vue·1024程序员节
星空的资源小屋12 小时前
Antares SQL,一款跨平台开源 SQL 客户端
数据库·人工智能·pdf·开源·电脑·excel·1024程序员节
2501_9159184114 小时前
iOS 26 查看电池容量与健康状态 多工具组合的工程实践
android·ios·小程序·https·uni-app·iphone·webview
羑悻的小杀马特15 小时前
告别内网限制!用StirlingPDF+cpolar打造可远程访问的PDF工具站
pdf·cpolar·1024程序员节·stirlingpdf
2501_9159090616 小时前
iOS 架构设计全解析 从MVC到MVVM与使用 开心上架 跨平台发布 免Mac
android·ios·小程序·https·uni-app·iphone·webview