需求场景
1、实现截取当前页面的数据,并生成文件
方案1、html2canvs实现截取图片并转换为图片文件
import html2Canvas from 'html2canvas'
export const getJpeg = (dom, fileName) => {
return new Promise(resolve => {
html2Canvas(dom).then(canvas => {
const jpeg = canvas.toDataURL('image/jpeg', 1.0)
// resolve(new Blob([jpeg]));
resolve(base64ToFile(jpeg, fileName))
})
})
}
// base64转化为file文件
const base64ToFile = (urlData, fileName) => {
const arr = urlData.split(',')
const mime = arr[0].match(/:(.*?);/)[1]
const bytes = atob(arr[1])
let n = bytes.length
const ia = new Uint8Array(n)
while (n--) {
ia[n] = bytes.charCodeAt(n)
}
return new File([ia], fileName + '.jpg', { type: mime })
}
方案2、html2canvs实现截取图片并生成PDF文件
1、获取截取图片的dom节点生产canvas对象,并生成图片
2、获取canvas宽高计算PDF分页
3、PDF采用默认A4纸的大小,上下左右padding20计算位置
4、当前图片高度按A4纸大小缩放后的高度大于页面高度,则增加页
5、待办问题,处理分页时连贯的图片信息被截断
解决方案:截取的页面需要按照页面的尺寸来动态的设置空的节点,来实现动态按组件分页
方案缺点:难以解决元素被截断问题,打印效果差,生成的图片质量差html2canvas有上限要求,前端无法直接通过接口调用方式生成pdf文件
export const getPdf = (dom, fileName) => {
const A4_WIDTH = 592.28
const A4_HEIGHT = 841.89
return new Promise(resolve => {
html2Canvas(dom, {
background: '#01195e',
useCORS: true,
allowTaint: true // 开启跨域
}).then(canvas => {
const contentWidth = canvas.width
const contentHeight = canvas.height
// 一页pdf显示html页面生成的canvas高度;
const pageHeight = contentWidth / A4_WIDTH * A4_HEIGHT
let leftHeight = contentHeight
// 页面偏移
let position = 20
// a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
const imgWidth = A4_WIDTH - 40
const imgHeight = imgWidth / contentWidth * contentHeight
const pageData = canvas.toDataURL('image/jpeg', 1.0)
const pdf = new JsPDF('', 'pt', 'a4')
// 有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
// 当内容未超过pdf一页显示的范围,无需分页
if (leftHeight < pageHeight) {
pdf.addImage(pageData, 'JPEG', 20, 20, imgWidth, imgHeight)
} else {
while (leftHeight > 0) {
pdf.addImage(pageData, 'JPEG', 20, position, imgWidth, imgHeight)
leftHeight -= pageHeight
position -= 841.89
// 避免添加空白页
if (leftHeight > 0) {
pdf.addPage()
}
}
}
pdf.save(fileName + '.pdf')
})
})
}
避免分页被截断
// 避免分页被截断
outPutPdfFn() {
const vm = this
const A4_WIDTH = 592.28
const A4_HEIGHT = 841.89
vm.$nextTick(() => {
// dom的id。
const target = document.getElementById('resume-page-detail')
const pageHeight = (target.scrollWidth / A4_WIDTH) * A4_HEIGHT
// 获取分割dom,此处为class类名为item的dom
const lableListID = document.getElementsByClassName('page-detail-item')
// 进行分割操作,当dom内容已超出a4的高度,则将该dom前插入一个空dom,把他挤下去,分割
for (let i = 0; i < lableListID.length; i++) {
const multiple = Math.ceil((lableListID[i].offsetTop + lableListID[i].offsetHeight) / pageHeight)
if (this.isSplit(lableListID, i, multiple * pageHeight)) {
const divParent = lableListID[i].parentNode // 获取该div的父节点
const newNode = document.createElement('div')
newNode.className = 'emptyDiv'
newNode.style.background = '#fff'
const _H = multiple * pageHeight - (lableListID[i].offsetTop + lableListID[i].offsetHeight)
newNode.style.height = _H + 30 + 'px'
newNode.style.width = '100%'
const next = lableListID[i].nextSibling // 获取div的下一个兄弟节点
// 判断兄弟节点是否存在
console.log(next)
if (next) {
// 存在则将新节点插入到div的下一个兄弟节点之前,即div之后
divParent.insertBefore(newNode, next)
} else {
// 不存在则直接添加到最后,appendChild默认添加到divParent的最后
divParent.appendChild(newNode)
}
}
}
getPdf(this.$refs.content, this.fileName)
document
.getElementsByClassName('emptyDiv')[0]
.parentNode.removeChild(document.getElementsByClassName('emptyDiv')[0])
})
},
// 判断是否需要添加空白div
isSplit(nodes, index, pageHeight) {
// 计算当前这块dom是否跨越了a4大小,以此分割
if (
nodes[index].offsetTop + nodes[index].offsetHeight < pageHeight &&
nodes[index + 1] &&
nodes[index + 1].offsetTop + nodes[index + 1].offsetHeight > pageHeight
) {
return true
}
return false
}
其他方案:
Puppeteer利用无头浏览器提供的浏览器生成PDF的能力
参考链接:
zhuanlan.zhihu.com/p/76237595?…
官方称:“Most things that you can do manually in the browser can be done using Puppeteer”,那么具体可以做些什么呢?
- 网页截图或者生成 PDF
- 爬取 SPA 或 SSR 网站
- UI 自动化测试,模拟表单提交,键盘输入,点击等行为
- 捕获网站的时间线,帮助诊断性能问题
- 创建一个最新的自动化测试环境,使用最新的 js 和最新的 Chrome 浏览器运行测试用例
- 测试 Chrome 扩展程序
生成PDF
demo:
// create.js
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.pdf({path: 'example.pdf'});
await browser.close();
})();
详细实现见: blog.csdn.net/zhai_865327…