pdf.js使用在Ios的webview上白屏

在浏览器中和安卓的webview中使用都没问题,但是Ios中的webview打开点开第三次时,只展示了第一页,第四次点开后就白屏不展示,并且报错:
null is not an object (evaluating 'groupCtx.scale')
问下原因,代码如下



<template>
  <div class="pdf-container" ref="Pdfcontent">
    <!--此处根据pdf的页数动态生成相应数量的canvas画布-->
    <canvas
      v-for="pageIndex in pdfPages"
      :id="`pdf-canvas-${pageIndex}`"
      :key="pageIndex"
    ></canvas>
  </div>
</template>

<script setup>
import * as PdfJs from 'pdfjs-dist/legacy/build/pdf.js'
import { ref, onMounted, nextTick } from 'vue'
import 'pdfjs-dist/build/pdf.worker.entry'

PdfJs.GlobalWorkerOptions.workerSrc = import(
  'pdfjs-dist/build/pdf.worker.entry'
)
let pdfDoc = ''
const pdfPages = ref(0)
let pdfScale = 1.0
const maxZoom = 40
const Pdfcontent = ref(null)
const props = defineProps({
  pdfUrl: String,
  isPdfReady: Boolean,
  pdfStatus: String,
})
const emit = defineEmits(['update:isPdfReady', 'update:pdfStatus'])
function funloadFile(url) {
  const loadingTask = PdfJs.getDocument(url)
  loadingTask.promise.then((pdf) => {
    pdfDoc = pdf
    pdfPages.value = pdfDoc.numPages

    pdf.getPage(1).then((res) => {
      const boxWidth = Pdfcontent.value.clientWidth - 20
      const [x1, , x2] = res._pageInfo.view
      const pageWidth = x2 - x1
      pdfScale = (boxWidth * (maxZoom / 10)) / pageWidth
    })

    nextTick(() => {
      renderPage(1) // 表示渲染第 1 页
    })
  })
}
// num 表示渲染第几页
function renderPage(num) {
  console.log('renderPage')
  pdfDoc.getPage(num).then((page) => {
    const canvasId = 'pdf-canvas-' + num // 第num个canvas画布的id
    const canvas = document.getElementById(canvasId)
    const ctx = canvas.getContext('2d')
    const viewport = page.getViewport({ scale: pdfScale })
    canvas.width = viewport.width
    canvas.height = viewport.height
    const clientWidth = Pdfcontent.value.clientWidth
    canvas.style.width = clientWidth + 'px'
    // 根据pdf每页的宽高比例设置canvas的高度
    canvas.style.height =
      clientWidth * (viewport.height / viewport.width) + 'px'
    const renderContext = {
      canvasContext: ctx,
      viewport,
    }
    page.render(renderContext)
    // 在第num页渲染完毕后,递归调用renderPage方法,去渲染下一页,直到所有页面渲染完毕为止
    if (num < pdfPages.value) {
      renderPage(num + 1)
    } else {
      emit('update:isPdfReady', true)
    }
  })
}

onMounted(() => {
  funloadFile(props.pdfUrl)
})
</script>
<style scoped>
.pdf-container {
  /* padding-right: 20px; */
  width: 100%;
  height: 100%;
  overflow: scroll;
  scrollbar-width: none; /* firefox */
  -ms-overflow-style: none; /* IE 10+ */
}
.pdf-viewer::-webkit-scrollbar {
  display: none; /* Chrome Safari */
}
</style>

这个问题可能是由于在iOS设备上,canvas的渲染性能问题导致的。你可以尝试以下方法来解决这个问题:

  1. 优化canvas的大小和缩放比例。确保canvas的大小适应设备的屏幕大小,同时避免使用过高的缩放比例,以减少渲染压力。

  2. 使用离屏canvas。将canvas绘制在一个新的canvas元素上,而不是直接在页面上绘制。这样可以避免因为页面重排和重绘导致的性能问题。示例代码如下:

<template>
  <div class="pdf-container" ref="Pdfcontent">
    <!--此处根据pdf的页数动态生成相应数量的canvas画布-->
    <canvas
      v-for="pageIndex in pdfPages"
      :id="`pdf-canvas-${pageIndex}`"
      :key="pageIndex"
    ></canvas>
  </div>
</template>

<script>
import * as PdfJs from 'pdfjs-dist/legacy/build/pdf.js'
import { ref, onMounted, nextTick } from 'vue'
import 'pdfjs-dist/build/pdf.worker.entry'

PdfJs.GlobalWorkerOptions.workerSrc = import(
  'pdfjs-dist/build/pdf.worker.entry'
)
let pdfDoc = ''
const pdfPages = ref(0)
let pdfScale = 1.0
const maxZoom = 40
const Pdfcontent = ref(null)
const props = defineProps({
  pdfUrl: String,
  isPdfReady: Boolean,
  pdfStatus: String,
})
const emit = defineEmits(['update:isPdfReady', 'update:pdfStatus'])
function funloadFile(url) {
  // ...省略其他代码
}

onMounted(() => {
  funloadFile(props.pdfUrl)
})
</script>

<style scoped>
.pdf-container {
  /* padding-right: 20px; */
  width: 100%;
  height: 100%;
  overflow: scroll;
  scrollbar-width: none; /* firefox */
  -ms-overflow-style: none; /* IE 10+ */
}
.pdf-viewer::-webkit-scrollbar {
  display: none; /* Chrome Safari */
}
</style>
  1. 如果以上方法仍然无法解决问题,你可以考虑使用其他的PDF阅读器库,例如react-native-pdf-viewer。

【以下回答由 GPT 生成】

根据给出的代码和问题描述,我可以看到你正在使用pdf.js在iOS的webview上展示PDF文档。问题出现在第三次打开后只展示了第一页,第四次打开后变成白屏,并报错"null is not an object (evaluating 'groupCtx.scale')"。

这个问题可能是由于PDF文档没有正确地被释放导致的。为了解决这个问题,你可以尝试在每次加载新的PDF文档之前,先释放之前的文档。下面是具体的解决方案:

首先,你可以在Vue组件的beforeUnmount钩子中添加一个方法来释放PDF文档,如下所示:

<script setup>
import { onBeforeUnmount } from 'vue'

onBeforeUnmount(() => {
  if (pdfDoc) {
    pdfDoc.destroy()
  }
})
</script>

这样,在组件被销毁之前,会先执行这个方法来释放PDF文档。

接下来,你需要更新funloadFile方法,在每次加载新的PDF文档之前,先调用pdfDoc.destroy()释放之前的文档。修改后的代码如下:

function funloadFile(url) {
  if (pdfDoc) {
    pdfDoc.destroy()
  }

  const loadingTask = PdfJs.getDocument(url)
  loadingTask.promise.then(function (pdf) {
    pdfDoc = pdf
    pdfPages.value = pdf.numPages
    emit('update:isPdfReady', true)
    emit('update:pdfStatus', '')
    renderPages()
  })
}

通过以上的修改,你可以在加载新的PDF文档之前先释放之前的文档,从而解决在iOS的webview上使用pdf.js出现白屏问题的情况。

注意:这个解决方案是基于我对问题的理解和经验的推测,因为我没有具体的环境和设备来测试这段代码,所以无法百分之百保证解决了问题。如果这个解决方案无效,请提供更多的信息和代码,以便我能更好地帮助你解决问题。



【相关推荐】



如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^