浏览器端、H5移动端加载预览pdf文件(Pdf.js的使用)

web、H5、vue等预览pdf文件(Pdf.js)

Pdf.js官方文档:文档地址

1. 使用场景

  • 在浏览器中展示PDF文件内容:使用Html5的canvas元素来展示pdf文件。
  • 支持基本的浏览功能:PDF.js提供了一套用户界面,包括缩放、滚动、翻页等浏览功能,使用户能够方便地导航和浏览PDF文件。

2. 使用方法

  • web浏览器中使用

    1. 引入pdf.js文件.需要使用pdf.js文件和pdf.worker.js文件。

      // 引入 pdf.js 文件
      <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.js"></script>
      
    2. 编码示例(2.x版本示例)

      <!DOCTYPE html>
      <html>
      <head>
        <title>PDF.js Example</title>
        <style> #pdf-container { width: 800px; height: 600px; overflow: scroll; } </style>
      </head>
      <body>
        <div id="pdf-container"></div>
        <button id="prev-btn">Previous</button>
        <button id="next-btn">Next</button>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.js"></script>
        <script>
          // 指定工作线程脚本的路径
          pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.worker.js'
          var container = document.getElementById('pdf-container')
          // 放入pdf文件链接地址
          pdfjsLib.getDocument('https://oss.xxxxxxxxxxxxx.pdf').promise.then(function (pdf) {
            var currentPage = 1
            function renderPage(pageNumber) {
              container.innerHTML = '' // 清空容器
              pdf.getPage(pageNumber).then(function (page) {
                var scale = 1.2
                var viewport = page.getViewport({ scale: scale })
                var canvas = document.createElement('canvas')
                var context = canvas.getContext('2d')
                canvas.width = viewport.width
                canvas.height = viewport.height
                page.render({
                  canvasContext: context,
                  viewport: viewport
                })
                container.appendChild(canvas)
                currentPage = pageNumber
              })
            }
            // 监听翻页按钮点击事件
            document.getElementById('prev-btn').addEventListener('click', function () {
              if (currentPage > 1) { renderPage(currentPage - 1) }
            })
            document.getElementById('next-btn').addEventListener('click', function () {
              if (currentPage < pdf.numPages) { renderPage(currentPage + 1) }
            })
            renderPage(1)
          })
        </script>
      </body>
      </html>
      
    3. 最新版本(4.x)示例

      <!DOCTYPE html>
      <html>
      <head>
        <meta charset="UTF-8">
        <title>pdf example</title>
      </head>
      <body>
      <canvas id="the-canvas" style="border: 1px solid black; direction: ltr;"></canvas>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.1.392/pdf.min.mjs" type="module"></script>
      <script id="script" type="module">
        // url是pdf文件的链接地址
        const url = 'https://oss.xxxxxxxxxxx.pdf'
        pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.1.392/pdf.worker.mjs'
        const loadingTask = pdfjsLib.getDocument(url)
        const pdf = await loadingTask.promise
        const page = await pdf.getPage(1)
        const scale = 1.5
        const viewport = page.getViewport({ scale })
        const outputScale = window.devicePixelRatio || 1
        const canvas = document.getElementById("the-canvas")
        const context = canvas.getContext("2d")
        canvas.width = Math.floor(viewport.width * outputScale)
        canvas.height = Math.floor(viewport.height * outputScale)
        canvas.style.width = Math.floor(viewport.width) + "px"
        canvas.style.height = Math.floor(viewport.height) + "px"
        const transform = outputScale !== 1
          ? [outputScale, 0, 0, outputScale, 0, 0]
          : null
        const renderContext = {
          canvasContext: context,
          transform,
          viewport,
        }
        page.render(renderContext)
      </script>
      
      <pre id="code"></pre>
      </body>
      </html>
      
  • vue3组件中使用(直接上代码)

    <template>
      <div class="pdf-container" v-loading="loading">
        <canvas id="the-canvas"></canvas>
        <div class="change-page-btns">
          <el-button type="primary" @click="changePage('prev')">上一页</el-button>
          &nbsp;&nbsp;<span> {{ currPageNum }} / {{ pageTotal }} </span>&nbsp;&nbsp;
          <el-button type="primary" @click="changePage('next')">下一页</el-button>
        </div>
      </div>
    </template>
    
    <script setup lang="ts">
    /**
     * 在npm.org modules 市场没有找到对应的 pdf.js 应用,所以这里继续使用cdn网络,或者把代码下载到本地调用
     * https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.1.392/pdf.worker.mjs
     * https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.1.392/pdf.mjs
     */
    import * as pdfjsLib from 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.1.392/pdf.mjs'
    import { ref, onMounted, reactive} from 'vue'
    
    import { ElMessage } from 'element-plus'
    
    const filePath = ref('https://oss.xxxxx.pdf') // 要展示的pdf文件链接地址
    const loading = ref(false)
    let CurrPdfInfo:any = reactive({})
    const pageTotal = ref(1)
    const currPageNum = ref(1) // 默认展示pdf文件的第一页
    
    onMounted(() => {
      init()
    })
    
    const init = async () => {
      currPageNum.value = 1
      loading.value = true
      pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/4.1.392/pdf.worker.mjs'
      const loadingTask = pdfjsLib.getDocument(filePath.value)
      CurrPdfInfo = await loadingTask.promise
      pageTotal.value = CurrPdfInfo.numPages || 0
      loading.value = false
      RenderPage()
    }
    
    const RenderPage = async () => {
      const page = await CurrPdfInfo.getPage(currPageNum.value)
      const scale = 1
      const viewport = page.getViewport({ scale })
      const outputScale = window.devicePixelRatio || 1
      const canvas:any = document.getElementById("the-canvas") || null
      const context:any = canvas.getContext("2d")
      canvas.width = Math.floor(viewport.width * outputScale)
      canvas.height = Math.floor(viewport.height * outputScale)
      canvas.style.width = Math.floor(viewport.width) + "px"
      canvas.style.height = Math.floor(viewport.height) + "px"
      const transform = outputScale !== 1
        ? [outputScale, 0, 0, outputScale, 0, 0]
        : null
      const renderContext = {
        canvasContext: context,
        transform,
        viewport,
      }
      page.render(renderContext)
    }
    
    const changePage = (type:string) => {
      if (currPageNum.value === 1 && type === 'prev') {
        ElMessage.info('您已经操作到第一页!')
      } else if (currPageNum.value === pageTotal.value  && type === 'next') {
        ElMessage.info('您已经操作到最后一页!')
      } else {
        if (type === 'prev') { // 上一页
          currPageNum.value > 1 ? currPageNum.value-- : currPageNum.value = 1
        } else if (type === 'next') { // 下一页 CurrPdfInfo
          currPageNum.value < pageTotal.value ? currPageNum.value++ : currPageNum.value = pageTotal.value
        }
        RenderPage()
      }
    }
    
    </script>
    
    <style scoped>
    .pdf-container {
      width: 100%;
      height: 800px;
      border: 1px solid red;
      overflow: scroll;
    }
    </style>
    
    
  • uni-app H5中使用(新版本参考vue实现方式),以下是 **@dcloudio/uni-app-plus -v2.0.0 **为例来实现。---uniapp其他打包方式有原生api支持:uni.openDocument(OBJECT)

    // 此代码仅使用与uniapp打包成H5适用, 其他打包方式uni.openDocument(OBJECT)原生方法即可实现。
    
    // 项目入口index.html文件中要引入 js 文件
    // <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.js"></script>
    
    <template>
      <scroll-view class="scroll-container" @scrolltoupper="loadPerPage" @scrolltolower="loadNextPage" scroll-y="true" scroll-x="true">
        <view id="pdf-container"></view>
      </scroll-view>
    </template>
    
    <script>
    export default {
      name: 'scanPdf',
      data () {
        return {
          infoData: '',
          container: null, // 渲染pdf的canvas容器
          currPageNum: 1, // 默认渲染第一页
          pageTotal: 1,
          loadPageCount: 1,
          CurrPdfInfo: null,
          url: 'https://oss.xxxx/demo-ui.pdf'
        }
      },
      mounted () {
        this.initPdfViewer()
      },
      methods: {
        initPdfViewer () {
          this.currPageNum = 1
          this.loading = true
          uni.showLoading({title: '文件加载中...'})
          pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.worker.js'
          this.container = document.getElementById('pdf-container')
          pdfjsLib.getDocument(this.url).promise.then(pdf => {
            uni.hideLoading()
            this.pageTotal = pdf.numPages || 0 // pdf文件共有多少页
            this.CurrPdfInfo = pdf
            this.renderPage() // 初始化完成数据默认渲染第一页
          })
        },
        renderPage () {
          // this.container.innerHTML = '' // 清空容器
          this.CurrPdfInfo.getPage(this.currPageNum).then(page => {
            const scale = 1
            const viewport = page.getViewport({ scale: scale })
            const canvas = document.createElement('canvas')
            const context = canvas.getContext('2d')
            canvas.width = viewport.width
            canvas.height = viewport.height
            page.render({
              canvasContext: context,
              viewport: viewport
            })
            this.container.appendChild(canvas)
          })
        },
        loadNextPage () {
          if (this.loadPageCount <= this.currPageNum) {
            if (this.currPageNum < this.pageTotal) {
              this.currPageNum++
              this.loadPageCount = this.currPageNum
              this.renderPage()
            } else {
              this.currPageNum = this.pageTotal
              uni.showToast({
                title: '已经浏览到最后一页啦!',
                icon: 'none',
                mask: false
              })
            }
          }
        },
        loadPerPage () {
          uni.showToast({
            title: '已经浏览到第一页啦!',
            icon: 'none',
            mask: false
          })
        }
      }
    }
    </script>
    
    <style scoped>
    .scroll-container {
      width: 100%;
      height: 100%;
    }
    </style>
    
    
  • 有其他适配后续更新
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容