h5实现pdf预览

需求:上传多份PDF,可以挨个展示预览

技术栈:vue3

ui:vant4

问题:

1,需要适配浏览器,安卓和iOS系统

2,可以放大缩小

实现:使用pdfh5插件

代码:

复制代码
<template>
<van-swipe
            v-if="imageList.length > 0"
            ref="swipeRef"
            :touchable="true"
            :show-indicators="false"
            @change="onSwipeChange"
          >
            <van-swipe-item v-for="(img, index) in imageList" :key="index">
              <template v-if="isPdfFile(img)">
                <div class="pdf-container" @click="onPreview(img)" >
                  <div :id="`pdfh5-${index}`" class="pdfh5-wrapper"></div>
                </div>
              </template>
              <template v-else>
                <img :src="img" alt="xxx" class="invoice-image" @click="onPreview(img)" />
              </template>
            </van-swipe-item>
          </van-swipe>
</template>


<script setup>
import Pdfh5 from 'pdfh5'

import * as pdfjs from 'pdfjs-dist'
pdfjs.GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.11.174/build/pdf.worker.min.js'
// PDF 渲染相关
const pdfLoading = ref(false)
const pdfError = ref('')
let pdfh5Instance = null

const prevImage = () => {
  swipeRef.value?.prev()
}

const nextImage = () => {
  swipeRef.value?.next()
}

// 滑动切换时渲染 PDF
const onSwipeChange = (index) => {
  currentImageIndex.value = index + 1
  nextTick(() => {
    const currentImg = imageList.value[index]
    if (currentImg && isPdfFile(currentImg)) {
      renderPdf(currentImg, index)
    }
  })
}
// 判断是否为PDF文件
const isPdfFile = (url) => {
  if (!url) return false
  return url.toLowerCase().endsWith('.pdf') || url.includes('.pdf?')
}
// 使用 pdfh5 渲染 PDF
const renderPdf = (url, index) => {
  if (!url) return

  // 销毁旧实例
  if (pdfh5Instance) {
    pdfh5Instance.destroy()
    pdfh5Instance = null
  }

  const containerId = `pdfh5-${index}`

  // 延迟确保 DOM 元素已挂载
  setTimeout(() => {
    const container = document.getElementById(containerId)
    if (!container) {
      console.error('PDF 容器元素未找到:', containerId)
      pdfError.value = 'PDF 容器加载失败'
      return
    }

    try {
      pdfLoading.value = true
      pdfError.value = ''

      // 直接传入 DOM 元素而非选择器字符串
      pdfh5Instance = new Pdfh5(container, {
        pdfurl: url,
        lazy: false
      })

      // 监听准备开始渲染
      pdfh5Instance.on('ready', () => {
        console.log('PDF 总页数:', pdfh5Instance.totalNum)
      })

      // 监听加载完成
      pdfh5Instance.on('complete', (status, msg, time) => {
        console.log('PDF 加载完成:', status, msg, time)
        if (status === 'success') {
          pdfLoading.value = false
        }
      })

      // 监听错误
      pdfh5Instance.on('error', (err) => {
        console.error('PDF 加载失败:', err)
        pdfError.value = 'PDF 加载失败'
        pdfLoading.value = false
      })

    } catch (err) {
      console.error('PDFh5 初始化失败:', err)
      pdfError.value = 'PDF 加载失败'
      pdfLoading.value = false
    }
  }, 100)
}

// 预览图片或PDF
const previewVisible = ref(false)
const previewImage = ref('')
const previewPdf = ref('')
const onPreview = (img) => {
  console.log('img', img)
  window.open(img, '_blank')
  // if (isPdfFile(img)) {
  //   window.open(img, '_blank')
  // } else {
  //   previewImage.value = img
  //   previewVisible.value = true
  // }
}

// 监听图片列表变化,渲染 PDF
watch(imageList, (newList) => {
  if (newList.length > 0) {
    nextTick(() => {
      const currentImg = newList[currentImageIndex.value - 1]
      const index = currentImageIndex.value - 1
      if (currentImg && isPdfFile(currentImg)) {
        renderPdf(currentImg, index)
      }
    })
  }
}, { immediate: true })

// 组件卸载时销毁 pdfh5
onUnmounted(() => {
  if (pdfh5Instance) {
    pdfh5Instance.destroy()
    pdfh5Instance = null
  }
})
</script>

时间紧张,挑着把主要代码复制下来了~

相关推荐
志尊宝1 小时前
Vue3 零基础每日笔记(076):防抖节流的正确使用——搜索框、按钮防重复提交、滚动监听
javascript·vue.js·笔记
顽疲1 小时前
从零用 Java 实现小红书 SpringBoot Vue UniApp(23)笔记话题多对多:一条笔记进多个话题池
java·vue.js·spring boot
能源革命1 小时前
Vue 网格拖拽布局组件全景指南:7 大方案深度对比
前端·javascript·vue.js
daols882 小时前
vue 表格组件 vxe-table 实现自定义多行编辑功能
前端·javascript·vue.js·vxe-table
志尊宝2 小时前
Vue3 零基础每日笔记(075):图片懒加载与骨架屏
javascript·vue.js·笔记
ComPDFKit2 小时前
用 ComPDF DocSlight 提取 PDF 表格:三种样本实测与 Python 接入
开发语言·python·pdf·pdf表格提取
用户1733598075373 小时前
纯前端 PDF 压平避坑指南:压平后表单字段变了?
前端·javascript·vue.js
雪芽蓝域zzs3 小时前
第 4 节:点击地图添加 Marker 标记点
vue.js
雪芽蓝域zzs3 小时前
第 1 章:天地图 V4 + Vue3 + TS(UniApp / 若依可用)从零教学
vue.js
爱喝水的小周4 小时前
实验十 Vue‑Router 王者荣耀战绩查询 APP 开发实践
前端·javascript·vue.js