如何使用jspdf+html2canvas实现pdf预览打印

一、整体实现过程

  1. 为打印内容每个需要计算高度的dom节点添加同名类和唯一id
  2. 获取dom节点计算每个节点的高度,进行翻页
  3. 设置html2canvas和jspdf等参数转化为pdf

需要考虑的细节?

同名类可以使用uuidv4()生成唯一id添加到类名中方便获取,对于v-for循环的数据,需要计算高度的每个循环项需要添加唯一id

二、开始开发

1.使用dialog封装放入需要打印的内容

dialogPrint.vue

 <el-dialog v-if="dialogVisible"
               width="800px"
               v-dialogDrag
               :modal="true"
               destroy-on-close
               append-to-body
               custom-class='batchRecordSetUpEdit-dialog-body'
               :visible.sync="dialogVisible"
               :close-on-click-modal="false"
               :before-close="
        () => {
          dialogVisible = false;
        }
      ">
      <printContent :recordId="recordId"
                    :reportName="reportPeoples.user_name"
                    :reportTime="reportTime"
                    :userDeptName="userDeptName">
      </printContent>
      <span slot="footer"
            style="position: relative; z-index: 999">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary"
                   @click="showExportPDF = true"
                   v-else>导出PDF</el-button>

      </span>
    </el-dialog>

printContent.vue

<div class="batchRecordSetUpEdit-dialog-body scrollView-bar">
    <div class="content_top"
         id="content_top"
         :class="[`print-content-prtin-item-${recordId}`]">
      <div class="top_image">
        <div style="
           height:10px;"></div>
      </div>
      <div style="
           height:10px;"></div>
      <h2>工作周报</h2>
      <div style="
           height:20px;"></div>
    </div>
<div :class="[`print-content-prtin-item-${recordId}`]"  
v-for="(task,taskIndex) in project.task_list"
             :id="`task_list-${taskIndex}`"
             :key="taskIndex">
        <div :class="[`print-content-prtin-item-${recordId}`]">
{{item.name}}
</div>
</div>
    <div class="resume-container print-contrainer"></div>
  </div>

2.获取dom节点计算高度并进行翻页

 //导出pdf
    exportPDF (callback, type) {
      let ua = navigator.userAgent;
      if (/firefox/i.test(ua))
        return this.$alert(
          "此功能暂时无法在该浏览器上使用,请更换其他浏览器使用",
          "提示",
          {
            confirmButtonText: "确定",
            callback: action => { }
          }
        );
      // 获取所有子节点
      let doms = document.getElementsByClassName(
        `print-content-prtin-item-${this.recordId}`
      )
      // 维护一个数组,保存每个子节点的id和高度,代替doms进行增删改查操作
      // 由于doms节点数组不是数组,因此通过call进行遍历
      let data = Array.prototype.map.call(doms, item => {
        return {
          id: item.id,
          height: item.offsetHeight
        };
      });
      // dom节点的容器
      let pdfDom = document.createElement("div");
      pdfDom.id = "pdf";
      let domHeight = 0;
      let page = document.createElement("div");
      page.style.position = "relative";
      page.style.width = "760px";
      page.style.height = "1080px";
      page.style.padding = "20px";
      page.style.boxSizing = "border-box";
      // 遍历所有子节点   
      data.forEach((node, index) => {
        let dom = Array.prototype.filter.call(
          doms,
          item => item.id == node.id
        )[0];
        //查看节点高度
        if (domHeight + node.height < 950) {
          page.appendChild(dom.cloneNode(true));
          // table.appendChild(dom.cloneNode(true)); //插入表格实现合并边框
          domHeight += node.height;
          if (index == data.length - 1) {
            // setWaterMark("内部记录,禁止外传", page, 1080, 860);
            pdfDom.appendChild(page);
          }
        } else {
          let deepdom = dom.cloneNode(true)
          //获取新页面第一个tr节点
          let pagefirstDom = deepdom
          // 循环加入到容器中
          pdfDom.appendChild(page);
          page = null;
          page = document.createElement("div");
          page.classList.add("print-page");
          page.style.width = "760px";
          page.style.height = "1080px";
          page.style.padding = "20px";
          page.style.boxSizing = "border-box";
          page.style.position = "relative";
          page.appendChild(dom.cloneNode(true));
          domHeight = node.height;
          if (index == data.length - 1) {
            pdfDom.appendChild(page);
          }
        }
      });
      let container = document.getElementsByClassName("resume-container")[0];
      this.showExportPDF = false
      return new Promise((resolve, reject) => {
        this.getPdf("pdf", this.recordTitle, type).then(res => {
          if (res) {
            resolve(res)
          }
        })
        container.removeChild(pdfDom);
        if (callback) callback();
      })
    },

 3.封装getpdf函数进行html2canvas并成功进行jspdf转换

Vue.prototype.getPdf = function(id, title,type) {
  return new Promise(function(resolve,reject){
 //1.html2canvas将html页面转化为图片
 html2canvas(document.querySelector(`#${id}`), {
  useCORS: true, //看情况选用上面还是下面的,
  dpi: 1200,
  scale: 3, 
  allowTaint: true,
  taintTest: false
}).then(function(canvas) {
  let contentWidth = 2280;
  let contentHeight = canvas.height;
        //一页pdf显示html页面生成的canvas高度;
  let pageHeight = (contentWidth / 592.28) * 841.89;
        //未生成pdf的html页面高度
  let leftHeight = contentHeight;
  //页面偏移
  let position = 0;
  //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
  let imgWidth = 595.28;
  let imgHeight = (595.28 / contentWidth) * contentHeight;
  let pageData = canvas.toDataURL("image/jpeg", 1.0);

   //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
        //当内容未超过pdf一页显示的范围,无需分页
 
  //2.利用jspdf将图片的base64生成pdf文件
  let PDF = new JsPDF("", "pt", "a4");
  if (leftHeight < pageHeight) {
    PDF.addImage(pageData, "JPEG", 0, 0, imgWidth, imgHeight);
  } else {
    while (leftHeight > 0) {
      PDF.addImage(pageData, "JPEG", 0, position, imgWidth, imgHeight);
      leftHeight -= pageHeight;
      position -= 841.89
      if (leftHeight > 0) {
        PDF.addPage();
      }
    }
  }
  PDF.save(title + ".pdf");
});
  })
 
};

注:在转换过程中可能出现内容重叠之类的原因,这个需要对翻页高度或者转换html2canvas每页的高度进行调试

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值