8.30 笔记
场景
实现打印功能,后端返回的是一个png
的图片,需要前端展示图片并且将图片打印出来
实现图片展示思路
方法一
- 传过来的是一个
png
文件,不可能直接显示在页面上 - 图片展示主要借助
img
的src
属性,但是src
支持的属性值只有url
或者是图片的base64
,那么主要就是将图片转化为base64
- 首先调用
new blob([png文件],{type:类型})
,将png
转化为一个二进制格式进行读取 - 然后我们再将这个
blob
转化为base64(data:image/png;base64,xxxxx)
格式,我们调用FileReader()
它可以将File
或者Blob
对象转化为要读取的文件或者数据 FileReader
有一个onLoad
事件,是一个异步的事件,在文件成功读取时触发,我们可以在onload
里面去设置图片的src
const blob = new Blob([imgSrc], { type: 'image/png' })
// 获取图片路径
const objectUrl = URL.createObjectURL(blob)
imgRef.current!.src = objectUrl
方法二
- 思路和方法一类似,同样都是先转为
blob
格式 - 但是我们转为
blob
格式以后,调用了URL.createObjectURL()
这个方法,它可以将blob
转化为一个url
(这种url的格式是:blob:当前的网址) - 然后直接设置
src
即可
const blob = new Blob([imgSrc], { type: 'image/png' })
// 将二进制图片转换成base64
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = function (e) {
// 将base64里面的回车换行去掉
const base64 = (e.target?.result as string).replace(/[\r\n]/g, "");
imgRef.current!.src = base64;
}
方法三
这个方法是存在问题的,也是第一次想到的方法
当时后端展示的是一个url
,url
里面是一个网页,使用iframe
来直接展示这个网页,直接展示图片
但是存在的问题就是,打开的url
和开发环境的存在跨域问题,不能打开,并且后端无法改。
参考链接
FileReader - Web API 接口参考 | MDN
实现图片打印思路
方法一
这个方法存在问题
- 打印希望调用
window.print()
这个方法 - 所以在图片展示好了以后,我们直接获取了当前页面所有的
html元素
,并且也获取到了需要打印的图片 - 然后将它们进行调换
- 确实可以实现打印,但是当打印回来以后,整个页面就失去了活性
function printpage() {
let newstr = document.getElementById("printContent").innerHTML;
let oldstr = document.body.innerHTML;
document.body.innerHTML = newstr;
window.print();
document.body.innerHTML = oldstr;
return false;
}
原因:
- 因为重新写回来的只是一个页面,仅具有页面的样式和骨架,一些方法之类的已经全部丢掉了
- 假如你不在乎,可以直接调用
window.refresh()
强制刷新一下,让react
重新控制 - 但是这会导致一些选中的状态丢失
方法二
你可以打开一个新的窗口进行打印,调用window.open()
,然后页面打开以后打印,打印完成以后将新开的窗口关闭掉
但是这个问题会存在一个问题:我并不知道你什么时候会打印完毕,可能会出现打印还没结束,窗口就关闭了
并且window.open()
他是一个异步的,他会等当前所有的脚本块执行完成以后才会open
注意:调用window.open()方法以后,远程 URL 不会被立即载入,载入过程是异步的。(实际加载这个 URL 的时间推迟到当前脚本块执行结束之后。窗口的创建和相关资源的加载异步地进行。)
方法三
我们可以借助两个库HTML2Canvas
和print-js
两个库
export const printImg = (idName: string, src: string) => {
// 获取要导出的dom节点
const element = document.getElementById(idName);
return html2canvas(element as HTMLElement, {
useCORS: true, // 允许加载跨域的图片
allowTaint: true,
scale: 5, // 提升画面质量,但是会增加文件大小
height: 400, // 生成canvas的高度
width: 566, // 生成canvas的宽度
}).then((cs) => {
// 设置打印方向为横向
printJS({
printable: src,
type: 'image',
style: '@page { size:landscape; margin-left: 0; margin-top: 0; }'
});
}).catch((error) => {
console.log("报错", error);
});
}
HTML2Canvas
- 第一个参数:就是你需要截图的
dom
元素 - 第二个参数:就是一些options
这个方法是一个Promise
方法,在他的then()
函数里面,你可以获取到绘制好的canvas对象
,然后你可以调用canvas
的toDataUrl
将他转化为图片的src
,这时候只要设置src
就可以了
使用这个的思路:将当前这个dom
转化为图片,然后将这个图片使用PrintJs
进行打印
参考链接
Window.open() - Web API 接口参考 | MDN
html2canvas实现浏览器截图的原理(包含源码分析的通用方法)
揭秘 html2Canvas:打印高清 PDF 的原理解析 - 掘金
Print.js - Javascript library for HTML elements, PDF and image files printing.