前端打印HTML

129 阅读2分钟

前端打印

生成图片打印

所见即所得,体验效果好
无需重复调样式,减少工作量
问题图片模糊,内容截断,文字大小缩放

计算获取A4纸的长度(px)和高度(px)

 A4的标准尺寸: 210mm * 297mm
 屏幕的dpi: 1英寸(2.54cm)内有多少个像素px
 获取屏幕的dpi后即可计算出A4纸的物理长度对应的屏幕显示长度
 屏幕显示长度 = (dpi/2.54)*21
const getDpi = () => {
    if ( window.screen.deviceXDPI) {
        return [window.screen.deviceXDPI, window.screen.deviceYDPI];
    }
    const node = document.createElement( "div" );
    node.style = 'width:1in;height:1in;visibility:hidden;position:fixed;';
    document.body.appendChild(node);
    const dpi = [node.offsetWidth, node.offsetHeight];
    document.body.removeChild(node);
    return dpi;
}

const getA4Size = () => {
    const [x, y] = getDpi();
    return [(x/2.54)*21, (y/2.54)*29.7];
}

生成图片

 按照a4纸宽度设置要打印的dom节点,再调用html2canvas绘制生成一张长图
 字体模糊: 可放大canvas画布再绘制图片

分页

 根据a4高度切分图片分页
 避免切割到内容:从图片尾部开始遍历->判断该行是否存在非白色的像素点(判断该点是否为文字)->直到找到空白行
 
  async getImages() {
   const scale = 2;
   const a4Width = this.a4Size[0]*scale;
   const a4Height = this.a4Size[1]*scale;
   this.dom.style.width = `${this.a4Size[0]}px`;
   this.dom.style.display = 'block';
   const canvas = await html2canvas(this.dom, {
     useCORS: true,
     allowTaint: true,
     scale,
     backgroundColor: 'rgb(255, 255, 255)'
   });
   const ctx = canvas.getContext('2d');
   const width = canvas.width;
   const height = canvas.height;
   const list = [];
   let posY = 0;
   while(posY <= height) {
     const restHeight = height - posY;
     let posY2 = posY + Math.min(a4Height, restHeight);
     // 剩余的需要分页,找到空白行的位置切分
     if(restHeight > a4Height) { 
       posY2 = this.getBlankRow(ctx, posY2, width);
     }
     const img = this.getPageImage(canvas, posY, posY2, a4Height);
     list.push(img);
     posY = posY2 + 1;
   }
   this.dom.style.display = 'none';
   return list;
 }

 getBlankRow(ctx, y, width) {
   const data = ctx.getImageData(0, y, width, 1).data;
   let count = 0;
   for(let i = 0; i < data.length; i=i+4 ) {
     if (data[i] !== this.bgHex[0] || data[i+1] !== this.bgHex[1] || data[i+2] !== this.bgHex[2]) {
       count++;
     }
     if(count > 10) {
       return this.getBlankRow(ctx, y-1, width);
     }
   }
   return y;
 }

页眉页脚

 使用CSSRule
 使用canvas指令绘制

使用printJS打印图片

async toPrint() {
    const imgList = await this.getImages();
    printJS({
      documentTitle: this.title,
      printable: imgList,
      type: 'image',
      style: `
        @media print {
          @page {
            size: A4;
            margin: 10mm;
          }
          body {
            margin: 0;
            padding: 0;
          }
        }
      `,
      imageStyle: `
        width: 100%;
        margin: 0;
        padding: 0;
      `
    })
  }