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)

// 打印类属性、方法定义
/* 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.执行函数

 // 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.样式问题

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

.toPdf-black * {
  color: #000 !important;
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/934557.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Simdroid-EC:液冷仿真新星,助力新能源汽车电机控制器高效散热

近年来&#xff0c;新能源电动车的销量呈现出快速增长的态势。据统计&#xff0c;2024 年1-10月中国新能源汽车销量达728万辆&#xff0c;同比增长37.8%。 电机控制器在新能源汽车中对于保障动力和安全性能扮演着至关重要的角色&#xff0c;其核心部件IGBT&#xff08;绝缘栅双…

静态路由与交换机配置实验

1.建立网络拓扑 添加2台计算机&#xff0c;标签名为PC0、PC1&#xff1b;添加2台二层交换机2960&#xff0c;标签名为S0、S1&#xff1b;添加2台路由器2811&#xff0c;标签名为R0、R1&#xff1b;交换机划分的VLAN及端口根据如下拓扑图&#xff0c;使用直通线、DCE串口线连接…

深度学习:MindSpore自动并行

随着模型规模的逐渐增大&#xff0c;需要的算力逐渐增强&#xff0c;但是算力需求增长速度远高于芯片算力增长速度。现在唯一的解决方案只有通过超大规模集群训练大模型。 大集群训练大模型的挑战 内存墙 200B参数量的模型&#xff0c;参数内存占用745GB内存&#xff0c;训练…

前端成长之路:HTML(2)

HTML中有两个非常重要的标签——表格和表单&#xff0c;在介绍之前需要先了解表格和表单的区别&#xff1a;表格是用于展示数据的&#xff1b;表单是用于提交数据的。本文主要介绍表格。 表格标签 表格主要是用于显示、展示数据的&#xff0c;并非是页面布局。它可以使本来难…

如何使用WinCC DataMonitor基于Web发布浏览Excel报表文档

本文介绍使用 WinCC DataMonitor 的 "Excel Workbooks" 功能&#xff0c;通过 Excel 表格显示 WinCC 项目的过程值、归档变量值和报警归档消息。并可以通过 Web 发布浏览访问数据 1&#xff0e;WinCC DataMonitor是什么 ? DataMonitor 是 SIMATIC WinCC 工厂智能中…

Facebook广告突然无消耗?原因解析与解决方案。

在Facebook广告投放中&#xff0c;广告突然无消耗是很多广告主都会遇到的难题。这种情况不仅浪费时间&#xff0c;还可能导致营销活动停滞&#xff0c;影响业务发展。那么&#xff0c;广告无消耗的原因是什么&#xff1f;又该如何解决呢&#xff1f; 一、Facebook广告无消耗的…

安卓调试环境搭建

前言 前段时间电脑重装了系统&#xff0c;最近准备调试一个apk&#xff0c;没想到装环境的过程并不顺利&#xff0c;很让人火大&#xff0c;于是记录一下。 反编译工具下载 下载apktool.bat和apktool.jar 官网地址&#xff1a;https://ibotpeaches.github.io/Apktool/install…

shell基础知识4----正则表达式

一、文本搜索工具——grep grep -参数 条件 文件名 其中参数有以下&#xff1a; -i 忽略大小写 -c 统计匹配的行数 -v 取反&#xff0c;不显示匹配的行 -w 匹配单词 -E 等价于 egrep &#xff0c;即启用扩展正则表达式 -n 显示行号 -rl 将指定目录内的文件打…

git branch -vv(显示本地分支与远程分支的最新状态和提交信息)(very verbose mode)

文章目录 字段说明下一步操作建议字段说明当前状态分析相关操作建议 -vv功能说明-vv 与单个 -v 的区别总结 出现如下状况&#xff0c;是因为我把本地的develop分支没有提交到gitlab上的develop分支。 而是把develop分支的内容提交到了gitlab上的master分支&#xff0c;这样是不…

树莓派4B android 系统添加led灯 Hal 层

本文内容需要用到我上一篇文章做的驱动&#xff0c;可以先看文章https://blog.csdn.net/ange_li/article/details/136759249 一、Hal 层的实现 1.Hal 层的实现一般放在 vendor 目录下&#xff0c;我们在 vendor 目录下创建如下的目录 aosp/vendor/arpi/hardware/interfaces/…

Apache DolphinScheduler 限制秒级别的定时调度

背景 Apache DolphinScheduler 定时任务配置采用的 7 位 Crontab 表达式&#xff0c;分别对应秒、分、时、月天、月、周天、年。 在团队日常开发工作中&#xff0c;工作流的定时调度一般不会细化到秒级别。但历史上出现过因配置的疏忽大意而产生故障时间&#xff0c;如应该配…

MTK Android12 开机向导

文章目录 需求-场景参考资料&#xff1a;博客资料官网参考资料&#xff1a;参考资料注意点 附件资料文件说明&#xff1a;推荐工具&#xff1a;配置定制的 声明叠加层 APK需求实现替换字符、删减开机向导界面、添加开机向导界面删除部分界面需求&#xff0c;官网说明如下更新部…

Text2SQL(NL2sql)对话数据库:设计、实现细节与挑战

Text2SQL&#xff08;NL2sql&#xff09;对话数据库&#xff1a;设计、实现细节与挑战 前言1.何为Text2SQL&#xff08;NL2sql&#xff09;2.Text2SQL结构与挑战3.金融领域实际业务场景4.注意事项5.总结 前言 随着信息技术的迅猛发展&#xff0c;人机交互的方式也在不断演进。…

长沙数字孪生工业互联网三维可视化技术,赋能新型工业化智能制造工厂

长沙正积极拥抱数字化转型的浪潮&#xff0c;特别是在工业互联网和智能制造领域&#xff0c;长沙数字孪生技术的广泛应用&#xff0c;为新型工业化智能制造工厂的建设与发展注入了强劲动力。 在长沙智能制造工厂内&#xff0c;三维可视化技术被广泛应用于产线设计仿真优化和产…

FPGA工作原理、架构及底层资源

FPGA工作原理、架构及底层资源 文章目录 FPGA工作原理、架构及底层资源前言一、FPGA工作原理二、FPGA架构及底层资源 1.FPGA架构2.FPGA底层资源 2.1可编程输入/输出单元简称&#xff08;IOB&#xff09;2.2可配置逻辑块2.3丰富的布线资源2.4数字时钟管理模块(DCM)2.5嵌入式块 …

计算机网络期末常见问答题总结

1、试说明为什么在运输建立时使用三报文握手&#xff0c;如果不采用三报文握手会出现什么情况&#xff1f; TCP三次握手的目的是确保客户端和服务器都能够接收对方的连接请求,并建立起可靠的连接。如果只进行两次握手,可能会导致以下情况的发生: - 如果客户端发送的SYN包在网…

Redis篇-4--原理篇3--Redis发布/订阅(Pub/Sub)

1、概述 Redis 发布/订阅&#xff08;Publish/Subscribe&#xff0c;简称 Pub/Sub&#xff09;是一种消息传递模式&#xff0c;允许客户端订阅一个或多个通道&#xff08;channel&#xff09;&#xff0c;并接收其他客户端发布到这些通道的消息。 2、Redis 发布/订阅的主要概…

第六届地博会世界酒中国菜助力广州龙美地标美食公司推动地标发展

第六届知交会暨地博会&#xff1a;世界酒中国菜助力广州龙美地标美食公司推动地标产品创新发展 2024年12月9日至11日&#xff0c;第六届粤港澳大湾区知识产权交易博览会暨国际地理标志产品交易博览会在中新广州知识城盛大启幕。本届盛会吸引了全球众多知识产权领域的专业人士和…

【CSS in Depth 2 精译_074】第 12 章 CSS 排版与间距概述 + 12.1 间距设置(下):行内元素的间距设置

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第四部分 视觉增强技术 ✔️【第 12 章 CSS 排版与间距】 ✔️ 12.1 间距设置 12.1.1 使用 em 还是 px12.1.2 对行高的深入思考12.1.3 行内元素的间距设置 ✔️ 12.2 Web 字体12.3 谷歌字体 文章目…

基于FPGA的智能电子密码指纹锁(开源全免)

基于FPGA的智能电子密码指纹锁 一、功能描述硬件资源需求 二、整体框架知识准备AS608指纹模块4*4数字键盘模块 三、Verilog代码实现以及仿真验证1.AS608_data模块2.check_hand模块3.four_four_key模块4.check_mima模块5.change_mima模块6.seg_ctrl模块7.uart_top模块8.key_debo…