First of all, if the version of pdfjs dist is not installed correctly, there will be all kinds of bug s!!!
At present, the versions of pdfjs dist and nuxt in my project:
"nuxt": "^2.15.8",
"pdfjs-dist": "2.3.200",
1, Project background
Because the contract signing function in the company's project needs to involve the user preview contract function, my pain comes o(╥﹏╥) O
After the initial discussion of this function, the back-end returns the pdf link. The front-end students realize the effect of pdf Online preview. The effect diagram is as follows:
2, Function realization
At first, after searching on the Internet, I decided to use Vue pdf plug-in to realize the function of pdf preview. I realized the function in local development and released it to the test environment.
The most worrying thing happened. After being released to the formal environment, the whole project reported errors. I really vomited blood....
Uncaught DOMException: Failed to construct 'Worker': Script at 'http://a.com/ef3086d432cfbec65966.worker.js' cannot be accessed from origin 'http:/b.com'.
After some searching, we finally found the specific reason. It is because Vue pdf uses worker in order to speed up the rendering of pdf, because the static files of our project are placed on qiniu in the formal environment. However, worker cannot cross domain, and cross domain problems will occur in the scene where pages are separated from static resources-- Solve the problem of cross domain error reporting after Vue PDF packaging
3, Solution
node_ In modules / Vue PDF / SRC / vuepdfnosss.vue, there is a judgment supported by workers. In general Vue projects, you can directly comment it out and repackage it.
// notes if Two sentences of code or comments in the whole if sentence if ( typeof window !== 'undefined' && 'Worker' in window && navigator.appVersion.indexOf('MSIE 10') === -1 ) { // var PdfjsWorker = require('worker-loader!pdfjs-dist/build/pdf.worker.js'); // PDFJS.GlobalWorkerOptions.workerPort = new PdfjsWorker(); }
Comment out the above code, do not go to the web worker, and the page can run normally; In contrast, the page loading time may be longer and the performance may be reduced;
Note: because my project uses automated deployment, I will re npm i pull new packages every time I deploy, so I can't modify Vue PDF files locally
For the above reasons, I can only replace the plug-in and find the appropriate plug-in again. After some searching, it is replaced with pdfjs dist plug-in. The specific implementation is as follows:
<template> <div class="pdf-preview-container"> <div v-for="page in docPages" :key="page" ref="container" class="page-container" :style="{ height: `${pageHeight}px`, }" > <canvas v-if="renderList.includes(page)"> </canvas> </div> </div> </template> <script> export default { props: { url: { type: String, required: true, }, renderPages: { type: Number, default: 5, }, customScroll: { type: Boolean, default: false, }, offsetHeight: { type: Number, default: 0, }, }, data() { return { doc: null, docPages: 0, currentPage: 0, pageHeight: 0, renderList: [], } }, watch: { url: { immediate: true, handler() { this.getPDFFile() }, }, }, mounted() { if (!this.customScroll) { document.addEventListener('scroll', this.scroll) } }, beforeDestroy() { document.removeEventListener('scroll', this.scroll) }, methods: { getPDFFile() { if (!this.url) return this.currentPage = 0 const pdfJS = require('pdfjs-dist/build/pdf') const pdfjsWorker = require('pdfjs-dist/build/pdf.worker.entry') pdfJS.GlobalWorkerOptions.workerSrc = pdfjsWorker pdfJS.getDocument(this.url).then(pdf => { // console.log('pdf: ', pdf) this.doc = pdf this.docPages = pdf._pdfInfo.numPages this.$nextTick(() => { this.docPages && this.scrollToPage(1) }) }) }, scrollToPage(pageNo) { if (this.currentPage === pageNo) return this.currentPage = pageNo let list = [] for ( let page = pageNo - this.renderPages; page <= pageNo + this.renderPages; page++ ) { list.push(page) } list = list.filter(page => page <= this.docPages && page >= 1) this.$nextTick(() => { this.renderList = list this.renderList.forEach(page => { this.renderPage(page) }) }) }, // Render page renderPage(pageNo) { this.doc.getPage(pageNo).then(page => { // console.log('page: ', page) const container = this.$refs.container[pageNo - 1] if (!container) return const canvas = container.querySelector('canvas') if (!canvas || canvas.__rendered) return const ctx = canvas.getContext('2d') const dpr = window.devicePixelRatio || 1 const bsr = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1 const ratio = dpr / bsr const rect = container.getBoundingClientRect() const viewport = page.getViewport(1) const width = rect.width const height = (width / viewport.width) * viewport.height canvas.style.width = `${width}px` canvas.style.height = `${height}px` this.pageHeight = height canvas.height = height * ratio canvas.width = width * ratio ctx.setTransform(ratio, 0, 0, ratio, 0, 0) page.render({ canvasContext: ctx, viewport: page.getViewport(width / viewport.width), }) canvas.__rendered = true }) }, scroll() { this.checkRender(document.documentElement) }, checkRender(el) { if (!this.pageHeight) return let scrollTop = el.scrollTop if (el === document.documentElement) { scrollTop = el.scrollTop || window.pageYOffset || document.body.scrollTop } let page = Math.floor((scrollTop - this.offsetHeight) / this.pageHeight) page = Math.max(page, 1) page = Math.min(page, this.docPages) this.scrollToPage(page) }, }, } </script>
Call on page:
<template> <div id="app"> <pdf-preview :url="url"></pdf-preview> </div> </template> <script> import pdfPreview from "./components/PdfPreview.vue"; export default { name: "app", components: { pdfPreview, }, data() { return { url: "/static/pdf.pdf", }; }, }; </script>
Reference link: https://github.com/Lushenggang/pdf-preview
After some tossing, the problem was finally solved. I really spit blood.