vue2+html2canvas+js PDF实现试卷导出和打印功能

1.首先安装

import html2canvas from 'html2canvas';

import { jsPDF } from 'jspdf';

2.引入打印插件print.js

import Print from "@/assets/js/print";

Vue.use(Print)

javascript 复制代码
// 打印类属性、方法定义
/* eslint-disable */
const Print = function (dom, options) {
    if (!(this instanceof Print)) return new Print(dom, options);

    this.options = this.extend({
        'noPrint': '.no-print'
    }, options);

    if ((typeof dom) === "string") {
        this.dom = document.querySelector(dom);
    } else {
        this.isDOM(dom)
        this.dom = this.isDOM(dom) ? dom : dom.$el;
    }

    this.init();
};
Print.prototype = {
    init: function () {
        var content = this.getStyle() + this.getHtml();
        this.writeIframe(content);
    },
    extend: function (obj, obj2) {
        for (var k in obj2) {
            obj[k] = obj2[k];
        }
        return obj;
    },

    getStyle: function () {
        var str = "",
            styles = document.querySelectorAll('style,link');
        for (var i = 0; i < styles.length; i++) {
            str += styles[i].outerHTML;
        }
        str += "<style>" + (this.options.noPrint ? this.options.noPrint : '.no-print') + "{display:none;}</style>";
        // str += "<style>html,body,div{height: auto!important;font-size:14px}</style>";
        return str;
    },

    getHtml: function () {
        var inputs = document.querySelectorAll('input');
        var textareas = document.querySelectorAll('textarea');
        var selects = document.querySelectorAll('select');

        for (var k = 0; k < inputs.length; k++) {
            if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {
                if (inputs[k].checked == true) {
                    inputs[k].setAttribute('checked', "checked")
                } else {
                    inputs[k].removeAttribute('checked')
                }
            } else if (inputs[k].type == "text") {
                inputs[k].setAttribute('value', inputs[k].value)
            } else {
                inputs[k].setAttribute('value', inputs[k].value)
            }
        }

        for (var k2 = 0; k2 < textareas.length; k2++) {
            if (textareas[k2].type == 'textarea') {
                textareas[k2].innerHTML = textareas[k2].value
            }
        }

        for (var k3 = 0; k3 < selects.length; k3++) {
            if (selects[k3].type == 'select-one') {
                var child = selects[k3].children;
                for (var i in child) {
                    if (child[i].tagName == 'OPTION') {
                        if (child[i].selected == true) {
                            child[i].setAttribute('selected', "selected")
                        } else {
                            child[i].removeAttribute('selected')
                        }
                    }
                }
            }
        }
        return this.dom.outerHTML;
    },

    writeIframe: function (content) {
        var w, doc, iframe = document.createElement('iframe'),
            f = document.body.appendChild(iframe);
        iframe.id = "myIframe";
        //iframe.style = "position:absolute;width:0;height:0;top:-10px;left:-10px;";
        iframe.setAttribute('style', 'position:absolute;width:0;height:0;top:-10px;left:-10px;');
        w = f.contentWindow || f.contentDocument;
        doc = f.contentDocument || f.contentWindow.document;
        doc.open();
        doc.write(content);
        doc.close();
        var _this = this
        iframe.onload = function () {
            _this.toPrint(w);
            setTimeout(function () {
                document.body.removeChild(iframe)
            }, 100)
        }
    },

    toPrint: function (frameWindow) {
        try {
            setTimeout(function () {
                frameWindow.focus();
                try {
                    if (!frameWindow.document.execCommand('print', false, null)) {
                        frameWindow.print();
                    }
                } catch (e) {
                    frameWindow.print();
                }
                frameWindow.close();
            }, 10);
        } catch (err) {
            console.log('err', err);
        }
    },
    isDOM: (typeof HTMLElement === 'object') ?
        function (obj) {
            return obj instanceof HTMLElement;
        } :
        function (obj) {
            return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
        }
};
const MyPlugin = {}
MyPlugin.install = function (Vue, options) {
    // 4. 添加实例方法
    Vue.prototype.$print = Print
}
export default MyPlugin

3.执行函数

java 复制代码
 // loding等待
    toLoding() {
      this.loading = this.$loading({
        lock: true,
        text: 'Loading',
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.7)'
      });
      // 导出按钮显示状态
      this.pdfIsShowData = false;
      // 展开所有节点
      let activeNames = [];
      for (let i = 0; i < Object.keys(this.dataAll).length; i++) {
        activeNames.push((i));
      }
      this.activeNames = activeNames;
      // 展开所有子节点
      if (this.$refs.collapse && this.$refs.collapse.length > 0) {
        this.$refs.collapse.forEach((item, index) => {
          item.activeNames = ['0'];
        })
      }
      // 关闭滚动条
      this.isMaxHeight = false;
    },
    // 打印试卷
    printPaper() {
      // 等待节点全部展开
      this.toLoding();
      setTimeout(() => {
        this.$nextTick(() => {
          this.$print(this.$refs.printContent);
          setTimeout(() => {
            this.loading.close();
            this.pdfIsShowData = true;
          }, 1000)
        });
      }, 2000)
    },
    // 导出试卷
    exportPaper() {
      // 等待节点全部展开
      this.toLoding()
      setTimeout(() => {
        this.$nextTick(() => {
          // 获取目标元素
          const element = document.querySelector('.toPdf');
          // 使用 html2canvas 捕获快照
          html2canvas(element).then(canvas => {
            // 将 canvas 转换为图片数据
            const imgData = canvas.toDataURL('image/png');
            // 创建一个 jsPDF 实例
            const pdf = new jsPDF('p', 'mm', 'a4');
            const imgWidth = 210; // A4纸宽
            const pageHeight = 297; // A4纸高
            let imgHeight = canvas.height * imgWidth / canvas.width;
            let heightLeft = imgHeight;

            // 添加图像到 PDF 第一页
            let position = 0;
            pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
            heightLeft -= pageHeight;

            // 如果内容超过一页,则添加更多页
            while (heightLeft >= 0) {
              position = heightLeft - imgHeight;
              pdf.addPage();
              pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
              heightLeft -= pageHeight;
            }
            // 下载 PDF 文件
            pdf.save(`${this.testName}.pdf`);
            this.pdfIsShowData = true
            this.loading.close();
            this.$message({
              message: '导出成功',
              type: 'success'
            });
            // 关闭滚动条
            this.isMaxHeight = false;
          }).catch(error => console.error('Error capturing the snapshot:', error));
        });
      }, 2000)
    },

4.样式问题

打印时候把所有字体颜色改为黑色

css 复制代码
.toPdf-black * {
  color: #000 !important;
}

<div :class="{ 'toPdf': true, 'toPdf-black': !pdfIsShowData }" ref="printContent"

相关推荐
拓端研究室3 小时前
专题:2025人形机器人、工业机器人、智能焊接机器人、扫地机器人产业洞察报告 | 附158+份报告PDF、数据仪表盘汇总下载
microsoft·机器人·pdf
TextIn智能文档云平台4 小时前
复杂PDF文档结构化提取全攻略——从OCR到大模型知识库构建
pdf·ocr
会飞的小菠菜4 小时前
PDF文件中的广告二维码图片该怎么批量删除
pdf·删除·二维码·批量
一只花里胡哨的程序猿19 小时前
odoo打印pdf速度慢问题
pdf·odoo
灵海之森1 天前
Python将md转html,转pdf
pdf
阿幸软件杂货间1 天前
最新PDF版本!Acrobat Pro DC 2025,解压即用版
pdf·adobe acrobat·acrobat
星空的资源小屋1 天前
网易UU远程,免费电脑远程控制软件
人工智能·python·pdf·电脑
会飞的小菠菜1 天前
如何一次性将多个PPT幻灯片批量转换成PDF文档
pdf·powerpoint·ppt·批量·格式转换
somethingGoWay1 天前
wpf .netcore 导出pdf文件
pdf·wpf·.netcore
小白电脑技术2 天前
PDF教程|如何把想要的网页保存下来?
pdf·电脑