编程知识 cdmana.com

vue中利用html2canvas和jspdf实现html生成pdf并下载

1.utils里面新建htmlToPdf.js

import html2canvas from "html2canvas"
import JsPDF from "jspdf"

/**
 * @param ele要生成 PDF的DOM元素(容器)
 * @param padfName PDF文件生成后的文件名字
*/

export default {
  install(Vue, options) {
    Vue.prototype.getPdfFromHtml = function (ele, pdfFileName) {
      let eleW = ele.offsetWidth// 获得该容器的宽
      //   let eleH = ele.offsetHeight // 获得该容器的高
      let eleH = ele.scrollHeight// 获得该容器的高
      let eleOffsetTop = ele.offsetTop// 获得该容器到文档顶部的距离
      let eleOffsetLeft = ele.offsetLeft// 获得该容器到文档最左的距离
      var canvas = document.createElement("canvas")
      var abs = 0
      let win_in = document.documentElement.clientWidth || document.body.clientWidth// 获得当前可视窗口的宽度(不包含滚动条)
      let win_out = window.innerWidth// 获得当前窗口的宽度(包含滚动条)
      if (win_out > win_in) {
        // abs = (win_o - win_i)/2;    // 获得滚动条长度的一半
        abs = (win_out - win_in) / 2// 获得滚动条宽度的一半
      }
      canvas.width = eleW * 2// 将画布宽&&高放大两倍
      canvas.height = eleH * 2
      var context = canvas.getContext("2d")
      context.scale(2, 2) // 增强图片清晰度
      context.translate(-eleOffsetLeft - abs, -eleOffsetTop)
      html2canvas(ele, {
        dpi: 300,
        useCORS: true//允许canvas画布内可以跨域请求外部链接图片, 允许跨域请求。
      }).then(canvas => {
        var contentWidth = canvas.width
        var contentHeight = canvas.height
        //一页pdf显示html页面生成的canvas高度;
        var pageHeight = (contentWidth / 592.28) * 841.89 // 这样写的目的在于保持宽高比例一致 pageHeight/canvas.width = a4纸高度/a4纸宽度// 宽度和canvas.width保持一致
        //未生成pdf的html页面高度
        var leftHeight = contentHeight
        //页面偏移
        var position = 0
        //a4纸的尺寸[595.28,841.89],单位像素,html页面生成的canvas在pdf中图片的宽高
        var imgWidth = 595.28
        var imgHeight = (595.28 / contentWidth) * contentHeight
        var pageData = canvas.toDataURL("image/jpeg", 1.0)
        var pdf = new JsPDF("", "pt", "a4")
        //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
        //当内容未超过pdf一页显示的范围,无需分页
        if (leftHeight < pageHeight) {
          //在pdf.addImage(pageData, 'JPEG', 左,上,宽度,高度)设置在pdf中显示;
          pdf.addImage(pageData, "JPEG", 5, 0, imgWidth, imgHeight)
          // pdf.addImage(pageData, 'JPEG', 20, 40, imgWidth, imgHeight);
        } else {
          // 分页
          while (leftHeight > 0) {
            pdf.addImage(pageData, "JPEG", 5, position, imgWidth, imgHeight)
            leftHeight -= pageHeight
            position -= 841.89
            //避免添加空白页
            if (leftHeight > 0) {
              pdf.addPage()
            }
          }
        }
        pdf.save(pdfFileName + ".pdf")
      })
    }
  }
}

2.在main.js引入

import htmlToPdf from "../src/utils/htmlToPdf"
Vue.use(htmlToPdf)

 

3.点击按钮调用print方法

<!--
 * @Descriptions: 
 * @Version: 
 * @Author: 
 * @Date: 2020-12-24 17:35:44
 * @LastEditors: dongwenjie
 * @LastEditTime: 2020-12-25 09:56:46
-->
<template>
  <div id="htmltopdf">
    <img
      src="../../../public/static/img/back.jpg"
      alt=""
      width="400px"
      height="400px"
      crossOrigin="anonymous"
    />
    <el-form ref="form" :model="form" label-width="80px">
      <el-form-item label="活动名称">
        <el-input v-model="form.name"></el-input>
      </el-form-item>
      <el-form-item label="活动区域">
        <el-select v-model="form.region" placeholder="请选择活动区域">
          <el-option label="区域一" value="shanghai"></el-option>
          <el-option label="区域二" value="beijing"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="活动时间">
        <el-col :span="11">
          <el-date-picker
            type="date"
            placeholder="选择日期"
            v-model="form.date1"
            style="width: 100%"
          ></el-date-picker>
        </el-col>
        <el-col class="line" :span="2">-</el-col>
        <el-col :span="11">
          <el-time-picker
            placeholder="选择时间"
            v-model="form.date2"
            style="width: 100%"
          ></el-time-picker>
        </el-col>
      </el-form-item>
      <el-form-item label="即时配送">
        <el-switch v-model="form.delivery"></el-switch>
      </el-form-item>
      <el-form-item label="活动性质">
        <el-checkbox-group v-model="form.type">
          <el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
          <el-checkbox label="地推活动" name="type"></el-checkbox>
          <el-checkbox label="线下主题活动" name="type"></el-checkbox>
          <el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
        </el-checkbox-group>
      </el-form-item>
      <el-form-item label="特殊资源">
        <el-radio-group v-model="form.resource">
          <el-radio label="线上品牌商赞助"></el-radio>
          <el-radio label="线下场地免费"></el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item label="活动形式">
        <el-input type="textarea" v-model="form.desc"></el-input>
      </el-form-item>
    </el-form>
    <el-button type="primary" @click="print">生成pdf</el-button>
  </div>
</template>

<script>
export default {
  name: "htmltopdf",
  components: {},
  mixins: [],
  props: {},
  data() {
    return {
      form: {
        name: "",
        region: "",
        date1: "",
        date2: "",
        delivery: false,
        type: [],
        resource: "",
        desc: "",
      },
    };
  },
  computed: {},
  watch: {},
  created() {},
  mounted() {},
  methods: {
    print() {
      this.getPdfFromHtml(document.getElementById("htmltopdf"), "pdf");
    },
    onSubmit() {
      console.log("submit!");
    },
  },
};
</script>
<style lang="scss" scoped>
</style>

 

4.导出如图所示

版权声明
本文为[一生懸命吧]所创,转载请带上原文链接,感谢
https://my.oschina.net/u/4446873/blog/4839822

Scroll to Top