背景介绍
最近业务上评估了一个隐私协议文件预览的需求,最开始想了几个方案
1、B端后台提供富文本编辑器,由客户公司自行编辑(客户麻烦);
2、B端后台提供上传文件功能,C端实现预览(方便客户);
3、客户自行提供网页链接预览,配置在B端后台(客户麻烦);
秉着一切以客户使用简单为上的理念,最后选择的 第2个方案,以 pdf 作为介质,好处有以下几点:
1、方便客户,只需要维护一份 pdf 文件即可
2、方便开发,之前开发过解析 pdf 相关,代码可以复用;
3、C端小程序后台只需要配置一个业务地址即可;
缺点:
1、微信小程序 webview 嵌套h5可能存在兼容性问题,若 pdf 文件过大某些机型会出现闪退现象(目前解决办法是减少 pdf 大小😂)
着急使用的可参考:
https://wwf6d793ceba440218-qw-scrm-dev.dustess.com/mobile-mall/pdfRender.html?pdfUrl=你的xxxPDF文件.pdf
具体实现
安装及引入:
npm包形式:
npm install pdfjs-dist 或 yarn add pdfjs-dist
import PDFJS from 'pdfjs-dist';
import workerSrc from 'pdfjs-dist/build/pdf.worker.entry'
PDFJS.workerSrc = workerSrc;
本篇文章重点讲直接引入形式(方便大家使用):
https://cdn.jsdelivr.net/npm/pdfjs-dist@3.9.179/build/pdf.min.js
https://cdn.jsdelivr.net/npm/pdfjs-dist@3.9.179/build/pdf.worker.min.js
步骤一:加载 pdf.min.js
// 加载
const getPdfJs = async () => {
return new Promise((resolve, reject) => {
let script = document.createElement('script')
script.type = 'text/javascript'
script.src = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.9.179/build/pdf.min.js'
script.onload = () => {
resolve(pdfjsLib)
}
script.onerror = () => {
console.log('失败')
reject()
}
document.head.appendChild(script)
})
};
步骤二:获取 pdf 内容
const getContent = (pdfUrl: string) => {
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.9.179/build/pdf.worker.min.js'
if (pdfUrl) {
pdfjsLib.getDocument({
url: pdfUrl || '', // 此参数需要设为true
// cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.9.179/cmaps/', // 解决水印及相关字体渲染问题
cMapPacked: true
}).promise.then(pdf => {
console.log(pdf, 'pdf')
vm.pdf = pdf
// pdf内容,遍历加载到页面
loadPdf(pdf)
}).catch(() => {
console.log('文件地址请求失败')
})
} else {
console.error('未获取到地址')
}
}
步骤三:循环渲染 pdf 内容到页面
将 pdf 内容按照每页渲染到 canvas内,再将 canvas 保存生成为一张一张的 图片渲染到页面内
const loadPdf = (pdf: any) => {
try {
let scale = 2 // 页面内容比例
if (vm.pageNum <= pdf.numPages) {
pdf.getPage(vm.pageNum).then(page => { // 得到 PDF 文件的第一页
try {
let canvas = document.getElementById('pdf-canvas')
var viewport = page.getViewport({ scale }) // 根据 PDF 页面信息得到视图
var context = canvas.getContext('2d') // 指定 canvas 画布按 2D 方式渲染
// 设定画布大小
canvas.height = viewport.height
canvas.width = viewport.width
// 设定渲染参数
var renderContext = {
canvasContext: context,
viewport: viewport
}
// 渲染页面
let renderTask = page.render(renderContext)
renderTask.promise.then(() => {
let ctx = canvas.getContext('2d')
// 自己想加点文字水印可以在这里添加
// drawImg()
let base64Img = canvas.toDataURL()
vm.imgs.push(base64Img)
let contentBox = document.getElementById('content-box')
let oImg = document.createElement('img')
oImg.src = base64Img
contentBox.appendChild(oImg)
ctx.clearRect(0, 0, canvas.height, canvas.height)
vm.pageNum++
loadPdf(pdf)
})
} catch (e) {
console.log(e)
}
})
} else {
console.log(vm.imgs, 'imgs')
}
} catch (e) {
}
};
多余功能:画布添加自定义文字水印
// 自定义添加文字水印
function drawImg () {
let canvas = document.getElementById('pdf-canvas')
let ctx = canvas.getContext('2d')
var text = 'test wqs viewer'
ctx.globalAlpha = 0.3
ctx.font = '46px 黑体'
ctx.rotate(-20 * Math.PI / 180)
ctx.fillStyle = 'rgba(12,100,100,0.4)'
ctx.rotate('Math.PI/60')
for (let i of [1, 2, 3, 4, 5, 6, 7, 8]) {
ctx.fillText(text, i * 10, i * 200);
// ctx.fillText(text, -300 - i * 1, i * 200 + 50)
// ctx.fillText(text, 300 + i * 1, i * 200 + 100)
}
};
最终效果:
获取源码关注公众号【前端h5】:
发送:pdfjs
临时使用:
https://wwf6d793ceba440218-qw-scrm-dev.dustess.com/mobile-mall/pdfRender.html?pdfUrl=你的xxxPDF文件.pdf&title=你的标题名称