Skip to content

8.30 笔记

场景

实现打印功能,后端返回的是一个png的图片,需要前端展示图片并且将图片打印出来

实现图片展示思路

方法一

  1. 传过来的是一个png文件,不可能直接显示在页面上
  2. 图片展示主要借助imgsrc属性,但是src支持的属性值只有url或者是图片的base64,那么主要就是将图片转化为base64
  3. 首先调用new blob([png文件],{type:类型}),将png转化为一个二进制格式进行读取
  4. 然后我们再将这个blob转化为base64(data:image/png;base64,xxxxx)格式,我们调用FileReader()它可以将File或者Blob对象转化为要读取的文件或者数据
  5. FileReader有一个onLoad事件,是一个异步的事件,在文件成功读取时触发,我们可以在onload里面去设置图片的src
jsx
const blob = new Blob([imgSrc], { type: 'image/png' })
// 获取图片路径
const objectUrl = URL.createObjectURL(blob)
imgRef.current!.src = objectUrl

方法二

  1. 思路和方法一类似,同样都是先转为blob格式
  2. 但是我们转为blob格式以后,调用了URL.createObjectURL()这个方法,它可以将blob转化为一个url这种url的格式是:blob:当前的网址
  3. 然后直接设置src即可
jsx
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和开发环境的存在跨域问题,不能打开,并且后端无法改。

参考链接

Blob - Web API 接口参考 | MDN

FileReader - Web API 接口参考 | MDN

实现图片打印思路

方法一

这个方法存在问题

  1. 打印希望调用window.print()这个方法
  2. 所以在图片展示好了以后,我们直接获取了当前页面所有的html元素,并且也获取到了需要打印的图片
  3. 然后将它们进行调换
  4. 确实可以实现打印,但是当打印回来以后,整个页面就失去了活性
jsx
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;
}

原因:

  1. 因为重新写回来的只是一个页面,仅具有页面的样式和骨架,一些方法之类的已经全部丢掉了
  2. 假如你不在乎,可以直接调用window.refresh()强制刷新一下,让react重新控制
  3. 但是这会导致一些选中的状态丢失

方法二

你可以打开一个新的窗口进行打印,调用window.open(),然后页面打开以后打印,打印完成以后将新开的窗口关闭掉

但是这个问题会存在一个问题:我并不知道你什么时候会打印完毕,可能会出现打印还没结束,窗口就关闭了

并且window.open()他是一个异步的,他会等当前所有的脚本块执行完成以后才会open

注意:调用window.open()方法以后,远程 URL 不会被立即载入,载入过程是异步的。(实际加载这个 URL 的时间推迟到当前脚本块执行结束之后。窗口的创建和相关资源的加载异步地进行。)

方法三

我们可以借助两个库HTML2Canvasprint-js两个库

jsx
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对象,然后你可以调用canvastoDataUrl将他转化为图片的src,这时候只要设置src就可以了

使用这个的思路:将当前这个dom转化为图片,然后将这个图片使用PrintJs进行打印

参考链接

Window.open() - Web API 接口参考 | MDN

入门 | HTML2CANVAS 中文文档

html2canvas实现浏览器截图的原理(包含源码分析的通用方法)

深度使用html2canvas的经验总结 - 掘金

揭秘 html2Canvas:打印高清 PDF 的原理解析 - 掘金

Print.js - Javascript library for HTML elements, PDF and image files printing.