前言
- 打印功能的实现方式有很多种,在此将通过 print.js 来介绍打印功能的实现以及实现过程中遇到的一些问题
一、仅打印图片
- npm 安装
npm install print-js --save
- npm 安装时将库导入项目
import printJS from 'print-js'
示例
- HTML
<div ref="printMe" id="printMe">
<img class="print-file" slot="cover" alt="example" :src="url" />
</div>
- js
print({
printable: this.$refs.printMe, // 要打印的id / ref。
documentTitle: '审核材料', // 文档标题
type: 'html', // 可以是 html 、pdf、image, json 等。
targetStyles: ['*'], // 这样设置继承了页面要打印元素原有的css属性。
ignoreElements: [], // 传入要打印的div中的子元素id,使其不打印
onLoadingStart: () => {
console.log('loading-start')
},
onLoadingEnd: () => {
console.log('loading-end')
},
onPrintDialogClose: () => {
console.log('print-dialog-close')
},
onError: e => {
console.log('打印失败')
},
})
本示例以打印 HTML 为例,print.js 还可以打印 pdf、image, json,默认打印 PDF
二、打印图片和 PDF
如果我们要同时打印含有图片和 PDF,有两种方案
- 使用 canvas 把 PDF 转为图片
- 引入 vue-pdf 标签来做 PDF 的展示
- vue-pdf 的优点:不用自己转图片,缺点:虽然可以实现功能,但是打出来比较模糊,图片质量不高,客户接受程度太低。在此我们选择第一种方案
第一步:先下载 pdfjs,网址:PDF 下载地址,把 pdf.js、pdf.worker.js 文件放到项目中,然后在需要打印的页面引入
import * as pdfjsLib from './pdfjs/build/pdf.js'
第二步:html 代码添加一行代码,canvas 用来绘图
<canvas id="the-canvas" style="display: none"></canvas>
- HTML
<div ref="printMe" id="printMe">
<div v-for="(item, index) in array" :key="index">
<img class="print-file" slot="cover" alt="example" :src="item.url" />
</div>
</div>
<canvas id="the-canvas" style="display: none"></canvas>
<button @click="printFile">打印</button>
- js
// pdf 转图片
async changePdfToImg (url) {
const _this = this
let imgArr = []
pdfjsLib.workerSrc = 'pdf.worker.js'
let loadingTask = pdfjsLib.getDocument(url)
let res = await loadingTask.promise
let pageNum = res.numPages
for (let i = 1; i <= pageNum; i++) {
let page = await res.getPage(i)
let scale = 4
let viewport = page.getViewport(scale)
let canvas = document.createElement('canvas')
let context = canvas.getContext('2d')
canvas.height = viewport.height
canvas.width = viewport.width
let renderContext = {
canvasContext: context,
viewport: viewport,
}
await page.render(renderContext)
let imgUrl = canvas.toDataURL('image/jpeg', 1) //转换为base64
if (imgUrl) {
imgArr[i - 1] = imgUrl
}
//pdf全部画完结束后操作
if (imgArr.length == pageNum && !_this.isEmpty(imgArr)) {
let canvas2 = document.getElementById('the-canvas')
let context2 = canvas2.getContext('2d')
canvas2.height = viewport.height * pageNum
canvas2.width = viewport.width
let count = 0
for (let j = 0; j < imgArr.length; j++) {
let IMG = new Image()
IMG.src = imgArr[j]
IMG.width = viewport.width
IMG.height = viewport.height
IMG.onload = function () {
context2.drawImage(IMG, 0, viewport.height * j)
count++ //确保所有img渲染结束后操作
if (count == pageNum) {
let canvas = document.getElementById('the-canvas')
//赋值给img
_this.imgUrl = canvas.toDataURL('image/jpeg')
}
}
}
}
}
return imgArr
},
async printFile () {
const array = []
list.forEach((i, num) => {
const obj = {
url: '',
}
if (i.url.indexOf('.pdf') === -1) {
obj.url = i.url
array.push(obj)
} else {
this.changePdfToImg(i.url).then(res => {
for (let n = 0; n < res.length; n++) {
const obj = {
url: res[n],
}
array.push(obj)
}
})
}
})
await this.printFn(array)
}
print({
printable: this.$refs.printMe, // 要打印的id / ref。
documentTitle: '审核材料', // 文档标题
type: 'html', // 可以是 html 、pdf、image, json 等。
targetStyles: ['*'], // 这样设置继承了页面要打印元素原有的css属性。
ignoreElements: [], // 传入要打印的div中的子元素id,使其不打印
onLoadingStart: () => {
console.log('loading-start')
},
onLoadingEnd: () => {
console.log('loading-end')
},
onPrintDialogClose: () => {
console.log('print-dialog-close')
},
onError: e => {
console.log('打印失败')
},
})
注意
1.toDataURL方法参数
canvas.toDataURL('image/jpeg', 1)
toDataURL(type?: string, quality?: any): string;
- toDataURL 的第二个参数(图片质量)在平常使用中容易被忽略,如果图像格式支持可变质量(如“图像/jpeg”),则质量字段是 0.0 到 1.0(包括 0.0 到 1.0)范围内的数字,表示生成图像的所需质量级别。级别越高则越清晰,生成的文件也越大