H5移动端文件预览pdf

H5移动端文件预览pdf

需求:H5页面嵌入浙政钉,需要文件预览Pdf。
试用了多个插件,踩了很多坑,如果小伙伴有类似填坑经历,并成功解决,感谢留言指点!!!
先讲最终方案,兼容ios,安卓,鸿蒙多种系统手机,移动端和pc端的pdf预览方式 --- pdf.js + iframe。

成功案例 pdf.js + iframe

步骤一: 下载 pdf.js , pdfjs 下载地址:https://pan.baidu.com/s/1Meh_hSlwCPvN6wPKzYNfyQ

提取码:pdfj

或官网地址下载: https://mozilla.github.io/pdf.js/

步骤二: 把下载下来的文件夹,放到项目根目录文件夹下。注意:放在不会被打包压缩的地方,比如 public 或 static 文件夹中,因为后面会用到web 文件中的 view.html 对文件地址进行代理,对于该路径相当于读取静态资源。【注:viewer.html 是pdf 的查看器】
步骤三:新建一个组件,pdfjs.vue
    <template>
      <div>
        <iframe width="100%" style="height: 100vh;border:none;" :src="pdfSrc"></iframe>
        <van-button class="close" @click="closePdf">
          关闭
        </van-button>
      </div>
    </template>
    
    <script>
    export default {
      name: 'pdf',
      props: {
        pdfurl: {
          type: String,
        },
      },
      data(){
        return {
          pdfSrc: ''
        }
      },
      mounted() {
        console.log('pdfurl', this.pdfurl)
        // 此处,我是把文件夹放到public中,pdf文件夹就在打包完的根目录下,pdf/web/viewer.html
        this.pdfSrc = `${window.location.origin + window.location.pathname}pdf/web/viewer.html?file=${encodeURIComponent(this.pdfurl)}`
        console.log('pdfSrc', this.pdfSrc)
      },
      methods: {
        closePdf() {
          this.$emit('closePdf')
        }
      }
    }
    </script>
    
    <style scoped>
    .close {
      position: absolute;
      left: 0;
      bottom: 0;
      height: 80px;
      width: 100%;
      line-height: 40px;
      text-align: center;
      color:#367CFD;
      font-size: 36px;
      background: #fff;
      }
    </style>
步骤四: 使用
 <template>
      <div>
        <!-- ... -->
        <van-popup v-model="previewFile" position="bottom">
          <pdf :pdfurl="preFileUrl" @closePdf="closePdfFn"></pdf>
        </van-popup>
      </div>
    </template>
    <script>
      // 引入pdfjs组件
      import pdf from '../../components/pdfjs.vue'
      export default {
        components: {
          pdf
        },
        data() {
          return {
            previewFile: false,
            preFileUrl: '', // 'https://xxxx?key=xxx.pdf'
          }
        },
        mounted() {
        },
        methods: {
          oprenPdfFn() {
            this.previewFile = true
          },
          closePdfFn() {
            this.previewFile = false
          }
        }
      }
    </script>

其他踩了很多坑的方案,结果还是不行,时间关系没再仔细研究

经过下面几个插件的试用,发现ios都能展示,而且用a标签也可以展示,应该是内置了预览组件。安卓和鸿蒙就不行,自带浏览器也都是直接跳下载,谷歌浏览器可以预览。

1. 简单的前端处理方式:

url: 文件地址(一般为文件流形式)
a 标签, <a :href="url"></a>

window.open(url)  //新建窗口打开链接预览
window.location.href = 文档地址;  //本页面内跳转链接实现预览

iframe 预览:<iframe :src="url" width="100%" height="100vh"></iframe>

以上方式,部分浏览器 或 手机app不能直接打开,会自动回退成下载链接,比如鸿蒙,比如IE

iframe内嵌常见问题:https://blog.csdn.net/qq_35408366/article/details/128447408

2. pdfh5 预览(移动端,h5)

  1. npm install pdfh5 , (会报错,需要其他依赖,不能直接用提示的语句直接npm下载,依旧会报错,npm报错:These dependencies were not found:* canvas in ./node_modules/pdfh5/js/pdf.js* dommatrix/dist/d )

  2. npm install canvas@2.8.0 --ignore-scripts

  3. npm install --save dommatrix

  4. npm install --save web-streams-polyfill

  5. 运行就成功了,亲测可行,但是pc端运行打不开 pdf的文件【vue-pdf 和 pdfh5 不可同时引用】,而且需要点两次才能获取到 pdfh5 这个对象。

  6. 引用 pdfh5 和 css【关于css的引入方式,网上也有踩了很多坑的,下面这种是最佳方式,亲测可行】

javascript 复制代码
    import Pdfh5 from 'pdfh5'
    import 'pdfh5/css/pdfh5.css'
  1. 定义容器【id】

    javascript 复制代码
      <div id="pdf-content" style="height: 100%;width: 100%"></div>
      
      openPdf(url) {
          // pdfh5实例化时传两个参数:selector选择器,options配置项参数,会返回一个pdfh5实例对象,
          // 可以用来操作pdf,监听相关事件
          this.pdfh5 = new Pdfh5('#pdf-content', {
    	      pdfurl: url || this.preFileUrl,
    	      lazy: false, // 是否懒加载,默认false
    	      renderType: 'canvas', // canvas、svg,默认canvas
    	      maxZoom: 3, // 手势缩放最大倍数,默认3
    	      scrollEnable: true, // 是否允许pdf滚动,默认true
    	      zoomEnable: true,// 是否允许pdf手势缩放,默认true
    	      limit: 0, // 限制pdf加载最大页数,默认0不限制
    	      goto: 1,
    	      // 设置每一页pdf上的水印
    	      // logo: { src: require("@/assets/images/icon27.png"), x: 20, y: 70, width: 60, height: 60 },
          });
          console.log('pdfh5', this.pdfh5)
          // 监听pdf准备开始渲染,此时可以拿到pdf总页数
          this.pdfh5.on('ready', function(totalNum) {
          	console.log('总页数:' + totalNum);
          });
          // 监听pdf加载完成事件,加载失败、渲染成功都会触发
          this.pdfh5.on('complete', (status, msg, time) => {
          	console.log('状态:' + status + ',信息:' + msg + ',耗时:' + time + '毫秒');
          })
      },

vue2 和 vue3 代码举例: https://blog.csdn.net/u014212540/article/details/129408653

遇到的问题:

  1. 下载依赖,一直报错,无法正常运行,切换 node 和 npm 版本都无果。解决方式:参考上文1234,按次序下载依赖。
  2. pc端运行打不开 pdf 的文件【vue-pdf 和 pdfh5 冲突,不可同时引用,原因未细究】,而且需要点两次才能获取到 pdfh5 这个对象【未解决】
  3. 安卓直接打不开项目,ios可以正常打开且能预览

3.vue-pdf 预览

遇到问题:

  1. vue-pdf 默认只能显示第一页,通过获取总页数遍历解决。
  2. vue-pdf 默认不可手机端两指放大缩小,加 页面放大缩小:
javascript 复制代码
    <template>
    <div class="pdf_wrap">
     <div class="pdf_btn">
       <van-button @click="scaleD()">放大</van-button>
       <van-button @click="scaleX()">缩小</van-button>
       <van-button @click="clock()">顺时针</van-button>
       <van-button @click="counterClock()">逆时针</van-button>
     </div>
     <div class="pdf_list">
       <!-- src:pdf地址,page: 当前显示页 -->
       <pdf
         ref="pdf"
         v-for="i in numPages"
         :key="i"
         :src="src"
         :page="i"
         :rotate="pageRotate"
         style="width: 100%"></pdf>
     </div>
     <van-button class="close" @click="closePdf">
       关闭
     </van-button>
    </div>
    </template> 
    <script>
    import pdf from 'vue-pdf';
    import CMapReaderFactory from 'vue-pdf/src/CMapReaderFactory.js'
    // import pdf from 'vue-pdf/src/vuePdfNoSssNoWorker.vue';
    export default {
    components: {
     pdf,
    },
    props: {
     pdfurl: {
       type: String,
     },
    },
    data() {
     return {
       src: '',
       numPages: undefined,
       scale: 100,
       pageRotate: 0
     }
    },
    mounted() {
     console.log('pdf', pdf)
     this.loadPdf(this.pdfurl)
    },
    methods: {
     loadPdf(url) {
       console.log(url, 'url')
       this.src = pdf.createLoadingTask({
         url,
         // pdf内容文字丢失
         cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.5.207/cmaps/',//引入pdf.js字体
         cMapPacked: true,
         // 动态文字不展示问题
         CMapReaderFactory
       })
       console.log(this.src, 'src')
       this.src.promise.then(pdf => {
         console.log(pdf, 'pdf')
         this.numPages = pdf.numPages // 这里拿到当前pdf总页数
       }).catch(err => {
         console.log('err', err)
       })
       console.log(this.src, 'src11111')
     },
     closePdf() {
       this.$emit('closePdf')
     },
     //放大
     scaleD() {
       this.scale += 20;
       console.log('refs.pdf', this.$refs.pdf)
       if (this.$refs.pdf && this.$refs.pdf.length > 0) {
         this.$refs.pdf.forEach(pdfPage=>{
           pdfPage.$el.style.width = parseInt(this.scale) + '%';
         })
       } else {
         this.$refs.pdf.$el.style.width = parseInt(this.scale) + '%';
       }
     },
     //缩小
     scaleX() {
       if (this.scale === 100) {
         return;
       }
       this.scale += -20;
       if (this.$refs.pdf && this.$refs.pdf.length > 0) {
         this.$refs.pdf.forEach(pdfPage=>{
           pdfPage.$el.style.width = parseInt(this.scale) + '%';
         })
       } else {
         this.$refs.pdf.$el.style.width = parseInt(this.scale) + '%';
       }
     },
     // 顺时针
     clock() {
       this.pageRotate += 90;
     },
     // 逆时针
     counterClock() {
       this.pageRotate -= 90;
     }
    }
    }
    </script>
    <style  scoped>
    .pdf_btn button {
     color:#367CFD;
    }
    .pdf_wrap {
     background: #fff;
     height: 100vh;
     position: relative;
    }
    .pdf_list {
     height: 100vh;
     overflow: scroll;
    }
    .close {
     position: absolute;
     left: 0;
     bottom: 0;
     height: 60px;
     width: 100%;
     line-height: 40px;
     text-align: center;
     color:#367CFD;
     font-size:30px;
     background: #fff;
    }
    </style>
  1. vue-pdf 不太友好,网上有说用 vue-pdf-signature 替代,依旧一样的问题。

  2. 安卓显示不全,鸿蒙白屏,ios可以显示。

网上解决方法:https://blog.csdn.net/PokoMobula/article/details/103164795,未解决问题;https://blog.csdn.net/weixin_44612172/article/details/127783210, 未解决问题

  1. 引入上面的字体后,安卓直接白屏,iOS依然可以显示。问题依旧。

4.pfile 代理

javascript 复制代码
    let url = 'https://xxxx?key=xxx.pdf'
    let pfileUrl = 'http://www.pfile.com.cn/api/profile/onlinePreview?url='+encodeURIComponent(url)
    window.open(pfileUrl);

遇到问题:

  1. 三种手机系统都打不开,需要手动转跳到浏览器中打开,浏览器都能正常预览。

预测方案:按成功方案预测,iframe + pfile 代理,应该也能实现。

相关推荐
一名技术极客11 分钟前
Vue2 doc、excel、pdf、ppt、txt、图片以及视频等在线预览
pdf·powerpoint·excel·文件在线预览
熊的猫40 分钟前
JS 中的类型 & 类型判断 & 类型转换
前端·javascript·vue.js·chrome·react.js·前端框架·node.js
瑶琴AI前端1 小时前
uniapp组件实现省市区三级联动选择
java·前端·uni-app
会发光的猪。1 小时前
如何在vscode中安装git详细新手教程
前端·ide·git·vscode
我要洋人死2 小时前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人3 小时前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人3 小时前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR3 小时前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香3 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q2498596933 小时前
前端预览word、excel、ppt
前端·word·excel