美文网首页
vue print打印div样式丢失 (react通用)

vue print打印div样式丢失 (react通用)

作者: 时间煮鱼 | 来源:发表于2022-07-28 16:54 被阅读0次

    使用网上的print.js插件,打印发现样式丢失。

    解决方案 > 将html转成pdf,再打印pdf

    使用jspdf将需要打印的div转成pdf(转成的pdf样式不会丢失,因为pdf.js是将div转成canvas)

    安装jspdf

    npm install --save html2canvas
    
    npm install jspdf --save
    

    上代码

    utli.js 直接复制,注意outPutPdf方法入参即可

    import html2canvas from 'html2canvas';
    import jsPDF from 'jspdf';
    
    // base64转blob
    export function toBlob(base64Data) {
      let byteString = base64Data
      if (base64Data.split(',')[0].indexOf('base64') >= 0) {
        byteString = atob(base64Data.split(',')[1]); // base64 解码
      } else {
        byteString = unescape(base64Data.split(',')[1]);
      }
      // 获取文件类型
      const mimeString = base64Data.split(';')[0].split(":")[1]; // mime类型
    
      // ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区
      // let arrayBuffer = new ArrayBuffer(byteString.length) // 创建缓冲数组
      // let uintArr = new Uint8Array(arrayBuffer) // 创建视图
    
      const uintArr = new Uint8Array(byteString.length); // 创建视图
    
      for (let i = 0; i < byteString.length; i += 1) {
        uintArr[i] = byteString.charCodeAt(i);
      }
      // 生成blob
      const blob = new Blob([uintArr], {
        type: mimeString
      })
      // 使用 Blob 创建一个指向类型化数组的URL, URL.createObjectURL是new Blob文件的方法,可以生成一个普通的url,可以直接使用,比如用在img.src上
      return blob;
    };
    
    /**
     * 输出pdf
     * @param {*} idName  html元素
     * @param {*} pdfName  输出pdf文件名
     * @param {*} isDownload  是否直接下载
     * @param {*} isPrint 是否直接打印
     * @param {*} callback  执行后的回调  
     */
     export function outPutPdf(idName, pdfName, isDownload = false, isPrint = false, callback) {
      const element = document.getElementById(idName);  // 这个dom元素是要导出的pdf的div容器
      const w = element.offsetWidth;  // 获得该容器的宽
      const h = element.offsetHeight;  // 获得该容器的高
      const offsetTop = element.offsetTop; // 获得该容器到文档顶部的距离  
      const offsetLeft = element.offsetLeft; // 获得该容器到文档最左的距离
      const canvas = document.createElement("canvas");
      let abs = 0;
      const winI = document.body.clientWidth; // 获得当前可视窗口的宽度(不包含滚动条)
      const winO = window.innerWidth; // 获得当前窗口的宽度(包含滚动条)
      if (winO > winI) {
        abs = (winO - winI) / 2; // 获得滚动条宽度的一半
      }
      canvas.width = w * 2; // 将画布宽&&高放大两倍
      canvas.height = h * 2;
      const context = canvas.getContext('2d');
      context.scale(2, 2);
      context.translate(-offsetLeft - abs, -offsetTop);
      // 这里默认横向没有滚动条的情况,因为offset.left(),有无滚动条的时候存在差值,因此translate的时候,要把这个差值去掉
      html2canvas(element, {
        useCORS: true, // 允许加载跨域的图片
        allowTaint: true,
        scale: 2 // 提升画面质量,但是会增加文件大小
      }).then(cs => {
        const contentWidth = cs.width;
        const contentHeight = cs.height;
        // 一页pdf显示html页面生成的canvas高度
        const pageHeight = contentWidth / 592.28 * 841.89;
        // 未生成pdf的html页面高度
        let leftHeight = contentHeight;
        // 页面偏移
        let position = 0;
        // a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
        const imgWidth = 595.28;
        const imgHeight = 592.28 / contentWidth * contentHeight;
        const pageDate = cs.toDataURL('image/jpeg', 1.0);
    
        const pdf = new jsPDF('', 'pt', 'a4');
        // 有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面的高度(841.89)
        // 当内容未超过pdf一页显示的范围,无需分页
        if (leftHeight < pageHeight) {
          pdf.addImage(pageDate, 'JPEG', 0, position, imgWidth, imgHeight);
        } else { // 分页
          while (leftHeight > 0) {
            pdf.addImage(pageDate, 'JPEG', 0, position, imgWidth, imgHeight)
            leftHeight -= pageHeight;
            position -= 841.89;
            // 避免添加空白页
            if (leftHeight > 0) {
              pdf.addPage()
            }
          }
        }
        if (isDownload) {
          pdf.save(`${pdfName}.pdf`);
        } 
        if (isPrint) {
          const link = window.URL.createObjectURL(toBlob(pdf.output('datauristring')));
                const myWindow = window.open(link);
          myWindow.print();
        }
        callback && callback(pdf);
      })
    }
    

    需要打印部分

    <div id="printDiv"></div>
    
    

    vue 全部代码

    <template>
      <a-modal
        v-model="visible"
        :title="title"
        :maskClosable="false"
        centered
        :width="1000"
        @cancel="close"
      >
        <div id="printDiv">
          <div class="maintain-view-title" v-if="!pdfing">
            <span></span>
            <span class="maintain-view-title-label">入库单</span>
            <a @click="printChart">打印报表</a>
          </div>
          <div class="maintain-view-title pdfing" v-else>
            <span class="maintain-view-title-label">入库单</span>
          </div>
          <a-form class="viewForm" :colon="true" :label-col="{ span: 8 }" :wrapper-col="{ span: 15 }">
            <a-row>
              <a-col :span="8">
                <a-form-item label="入库单号">
                  <span>{{ viewInfo.accessNumber }}</span>
                </a-form-item>
              </a-col>
              <a-col :span="8">
                <a-form-item label="供应商">
                  <span>{{ viewInfo.supplier }}</span>
                </a-form-item>
              </a-col>
              <a-col :span="8">
                <a-form-item label="入库日期">
                  <span>{{ viewInfo.accessDate && $moment(viewInfo.accessDate).format('YYYY-MM-DD HH:mm:ss') }}</span>
                </a-form-item>
              </a-col>
            </a-row>
            <a-row>
              <a-col :span="8">
                <a-form-item label="仓库">
                  <span>{{ viewInfo.warehouse }}</span>
                </a-form-item>
              </a-col>
              <a-col :span="8">
                <a-form-item label="来源">
                  <span>{{ viewInfo.source }}</span>
                </a-form-item>
              </a-col>
              <a-col :span="8">
                <a-form-item label="经办人">
                  <span>{{ viewInfo.handledBy }}</span>
                </a-form-item>
              </a-col>
            </a-row>
            <a-row>
              <a-col :span="8">
                <a-form-item label="采购单号">
                  <span>{{ viewInfo.purchaseOrderNo }}</span>
                </a-form-item>
              </a-col>
              <a-col :span="8">
                <a-form-item label="发票号">
                  <span>{{ viewInfo.invoiceNo }}</span>
                </a-form-item>
              </a-col>
              <a-col :span="8">
                <a-form-item label="合同号">
                  <span>{{ viewInfo.contractNo }}</span>
                </a-form-item>
              </a-col>
            </a-row>
            <a-row>
              <a-col :span="8">
                <a-form-item label="入库类型">
                  <span>{{ viewInfo.accessType }}</span>
                </a-form-item>
              </a-col>
              <a-col :span="8">
                <a-form-item label="创建时间">
                  <span>{{ viewInfo.addTime }}</span>
                </a-form-item>
              </a-col>
              <a-col :span="8">
                <a-form-item label="备注">
                  <span>{{ viewInfo.content }}</span>
                </a-form-item>
              </a-col>
            </a-row>
          </a-form>
          <a-table
            style="marginTop: 10px;"
            class="table-basic"
            :columns="columns"
            :data-source="data"
            :pagination="false"
            :loading="loading"
            row-key="id"
          >
          </a-table>
        </div>
        <template slot="footer">
          <a-button key="back" type="primary" @click="close">取消</a-button>
        </template>
      </a-modal>
    </template>
    <script>
    import { outPutPdf } from "@/utils/util";
    import { getStorageOrderTopDetail, getStorageOrderBottomListNoPage } from "@/api/stock";
    export default {
      name: "StockStorageOrderViewModal",
      components: {},
      data() {
        return {
          visible: false,
          form: null,
          title: "出库确认",
          loading: false,
          viewInfo: {},
          columns: [
            {
              title: "序号",
              key: "index",
              customRender: (text, render, index) => {
                return index + 1
              },
              align: "center"
            },
            {
              title: "产品编号",
              key: "productNumber",
              dataIndex: "productNumber"
            },
            {
              title: "类别",
              key: "type",
              dataIndex: "type"
            },
            {
              title: "产品名称",
              key: "productName",
              dataIndex: "productName"
            },
            {
              title: "规格型号",
              dataIndex: "specifications",
              dataIndex: "specifications"
            },
            {
              title: "计量单位",
              key: "unit",
              dataIndex: "unit"
            },
            {
              title: "批次",
              key: "batch",
              dataIndex: "batch"
            },
            {
              title: "数量",
              key: "number",
              dataIndex: "number"
            },
            {
              title: "单价",
              key: "price",
              dataIndex: "price"
            },
            {
              title: "金额",
              key: "total",
              dataIndex: "total"
            },
            {
              title: "已入库",
              key: "inbound",
              dataIndex: "inbound"
            },
            {
              title: "未入库",
              key: "notInbound",
              dataIndex: "notInbound"
            }
          ],
          data: [],
          pdfing: false, // 打印中
        };
      },
      methods: {
        // 显示弹框
        show(id) {
          this.visible = true;
          // 获取上方数据
          getStorageOrderTopDetail({ id }).then(res => {
            if (res.code === 0) {
              this.viewInfo = res.data;
            }
          });
          // 获取下方表格数据
          this.getTableData(id);
        },
        /**
         * 关闭弹框
         */
        close() {
          this.visible = false;
          this.$emit("cancel");
        },
        // 获取表格数据
        getTableData(warehouseRegisterId) {
           const params = {
            warehouseRegisterId
          };
          getStorageOrderBottomListNoPage(params).then(res => {
            this.loading = false;
            if (res.code === 0) {
              this.data = res.data;
            } else {
              this.$common.showErrorMessage(res.msg || "请求出现错误,请稍后再试");
            }
          });
        },
        // 打印
        printChart() {
          this.pdfing = true;
          this.$nextTick(() => {
            outPutPdf('printDiv', '入库单', false, true, () => {
              this.pdfing = false;
            });
          });
        }
      }
    };
    </script>
    
    <style lang="less" scoped>
    .maintain-view-title {
      display: flex;
      justify-content: space-between;
      align-items: center;
      &.pdfing {
        justify-content: center;
      }
      .maintain-view-title-label {
        font-weight: bold;
        font-size: 1.5em;
      }
    }
    .container-title-block {
      display: flex;
      justify-content: space-between;
      margin-top: 10px;
    }
    .viewForm {
      /deep/.ant-form-item {
        margin-bottom: 0;
      }
    }
    </style>
    

    相关文章

      网友评论

          本文标题:vue print打印div样式丢失 (react通用)

          本文链接:https://www.haomeiwen.com/subject/ovsqwrtx.html