vue项目中导出PDF的两种方式

参考大家导出的方式,基本上是如下两种:

1.使用 html2Canvas + jsPDF  导出PDF, 这种方式什么都好,就是下载的pdf太模糊了。对要求好的pdf这种方式真是不行啊!

2.调用浏览器自身的方法。window.print() 来打印(打印时可选下载),这种方式打印出来很清楚,但纯在浏览器兼容问题。 谷歌浏览器比较好用点。

两种导出pdf清晰度对比:

--------------左边 html2canvas + jspdf;-----------------------------------------------右边window.print() 浏览器方式------------

              

方式一:html2canvas+jspdf

html2Canvas + jsPDF 导出普遍存在一个问题就是不太清楚的问题。目前我没有在网上找到合适 这种方式打印出清晰的PDF解决方案。

如果不是要求太高的这种方式还是可以用的。

这种方式实现的方法:

首先npm 下载两插件

npm i html2canvas jspdf --save-dev

在.vue文件中定义 要到导出 DOM 元素

<template>
    <div class="pdf-demo">

        <button @click="handleDown">jsPDF方式下载</button>
        <button @click="handleWindowPrint( ‘#demo‘, ‘电子合同‘ )">浏览器方式下载</button>

        <div id="demo" >

                #demo 中的内容导出成 PDF

        </div>

    </div>
</template>        

然后创建一个 htmlToPdf.js 文件 ,内容如下:

import html2canvas from ‘html2canvas‘;
import JsPDF from ‘jspdf‘;

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

function downloadPDF(ele, pdfName){

    let eleW = ele.offsetWidth;// 获得该容器的宽
    let eleH = ele.offsetHeight;// 获得该容器的高

    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;    // 获得滚动条宽度的一半
        // console.log(a, ‘新abs‘);
    }

    canvas.width = eleW * 2;    // 将画布宽&&高放大两倍
    canvas.height = eleH * 2;

    var context = canvas.getContext("2d");

    context.scale(2, 2);

    context.translate(-eleOffsetLeft -abs, -eleOffsetTop);
    // 这里默认横向没有滚动条的情况,因为offset.left(),有无滚动条的时候存在差值,因此
    // translate的时候,要把这个差值去掉

    // html2canvas(element).then( (canvas)=>{ //报错
    // html2canvas(element[0]).then( (canvas)=>{
    html2canvas( ele, {
        dpi: 300,
        // allowTaint: true,  //允许 canvas 污染, allowTaint参数要去掉,否则是无法通过toDataURL导出canvas数据的
        useCORS:true  //允许canvas画布内 可以跨域请求外部链接图片, 允许跨域请求。
    } ).then( (canvas)=>{

        var contentWidth = canvas.width;
        var contentHeight = canvas.height;
        //一页pdf显示html页面生成的canvas高度;
        var pageHeight = contentWidth / 592.28 * 841.89;
        //未生成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‘, 0, 0, imgWidth, imgHeight);
            // pdf.addImage(pageData, ‘JPEG‘, 20, 40, 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(pdfName);
    })

}

export default {
    downloadPDF
}

在 要导出 的PDF的.vue文件中, 如下是使用

引入:

import htmlToPdf from ‘yourPath /htmlToPdf‘;

点击     jsPDF方式下载  按钮 执行如下函数,即可导出pdf

        methods: {

            handleDown(){
                //导出PDF
                htmlToPdf.downloadPDF( document.querySelector(‘#demo‘),‘我的PDF‘);
            },

        }    

方式二:window.print()方法

  调用浏览的window.print() 方法, 这种方式实现的主要思路为: 点击 打印(下载)按钮,

>将要<body>标签内的内容替换成要打印的 DOM元素, 这样就可以避免打印 不想要打印的内容了。(如果项目中使用的UI框架,此时<head>标签内会自动移入一些样式,最后打印时把head内的不必要的内容也替换掉。)

>然后通过setTimeout()方法异步 调用 window.print(), 因为如果你要打印的 DOM元素 不是写的 行内样式 的话浏览器渲染DOM时,是需要时间的,如果直接同步调取 window.print() 方法会造成 内部样式表和外部样式表的样式丢失。

>调取完 打印后 使用 window.location.reload() 刷新页面,恢复body 、head 表情内的内容。

具体实现代码如下:

点击    浏览器方式下载  按钮 执行如下函数,即可导出pdf(打印界面可以选择  另存为PDF文件)

        methods: {

            //浏览器方式打印
            //ele 为  css ID选择器
            //fileName    生成的PDF文件名
            handleWindowPrint(ele, fileName){

                //去除页面不必要的 head 标签内  内容, 避免影响打印页 , title 为保存为 pdf 的文件时的 文件名
                document.head.innerHTML = ‘<meta charset="utf-8">\n‘ +
                    ‘ <title> ‘ + fileName + ‘</title>\n‘ +
                    ‘ <link rel="shortcut icon" href="http://192.168.29.50:8081/favicon.ico" type="image/x-icon" />\n‘ +
                    ‘ <meta name="format-detection" content="telephone=no">\n‘ +
                    ‘ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">\n‘ +
                    ‘ <meta name="viewport" content="width=device-width,initial-scale=1.0">\n‘ +
                    ‘ <link rel="stylesheet" href="./static/css/contract.css"/>‘;  //生成pdf的外部css样式

                //要打印的 内容 html
                document.body.innerHTML =  document.querySelector( ele ).outerHTML;

                // window.print();

                //转异步 等待dom元素渲染(样式)完毕在打印
                setTimeout( ()=>{
                    //打印
                    window.print();
                    //刷新页面
                    window.location.reload();
                },20 )

            },

        },       

大致就是这样子了。

github  Demo 地址:   https://github.com/Ta0hua/vue-pdf-demo

原文地址:https://www.cnblogs.com/taohuaya/p/10805585.html

时间: 2024-11-12 02:36:20

vue项目中导出PDF的两种方式的相关文章

使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 选择调用的进程为 24 i386 getuid sys_getuid1647 i386 getgid sys_getgid16 使用库函数API方式 使用C代码中嵌入汇编代码方式

实验--使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用(杨光)

使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 攥写人:杨光  学号:20135233 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验要求: 选择一个系统调用(13号系统调用time除外),系统调用列表参见http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/syscalls/sys

java中设置代理的两种方式

1 前言 有时候我们的程序中要提供可以使用代理访问网络,代理的方式包括http.https.ftp.socks代理.比如在IE浏览器设置代理. 那我们在我们的java程序中使用代理呢,有如下两种方式.直接上代码. 2 采用设置系统属性 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import jav

JavaWeb应用中初始化Log4j的两种方式

本文主要介绍了普通JavaWeb应用(基于Tomcat)中初始化Log4j的两种方式: 1.通过增加 InitServlet ,设置令其自启动来初始化 Log4j . 2.通过监听器 ServletContextListener 监听 ServletContext 的初始化事件来初始化 Log4j . 先来看下方式一,直接上代码: web.xml 编写如下: 1 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 2 xmlns

基于Maven的SpringBoot项目实现热部署的两种方式

下面我将介绍使用maven构建的SpringBoot项目中实现热部署的两种方式,使得部署变得异常简单,同时两种方式也非常的简单. 热部署 devtools Pom.xml中直接添加依赖即可: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>provided</

Spring Boot 中实现定时任务的两种方式

在 Spring + SpringMVC 环境中,一般来说,要实现定时任务,我们有两中方案,一种是使用 Spring 自带的定时任务处理器 @Scheduled 注解,另一种就是使用第三方框架 Quartz ,Spring Boot 源自 Spring+SpringMVC ,因此天然具备这两个 Spring 中的定时任务实现策略,当然也支持 Quartz,本文我们就来看下 Spring Boot 中两种定时任务的实现方式. @Scheduled 使用 @Scheduled 非常容易,直接创建一个

JAVA中Arrays.sort()使用两种方式(Comparable和Comparator接口)对对象或者引用进行排序

一.描述 自定义的类要按照一定的方式进行排序,比如一个Person类要按照年龄进行从小到大排序,比如一个Student类要按照成绩进行由高到低排序. 这里我们采用两种方式,一种是使用Comparable接口:让待排序对象所在的类实现Comparable接口,并重写Comparable接口中的compareTo()方法,缺点是只能按照一种规则排序. 另一种方式是使用Comparator接口:编写多个排序方式类实现Comparator接口,并重写新Comparator接口中的compare()方法,

JAVA中创建字符串的两种方式的区别

我们知道,通常在Java中创建一个字符串会有两种方式,通过双引号直接赋值和通过构造器来创建. String x = "abcd"; String y = new String("abcd"); 然而,这两种方式之间的区别是什么?分别应用于哪些情况,之前还不是很懂. 1.双引号的方式 String x = "abcd"; String y = "abcd"; System.out.println(x==y);//true Sys

Direct3D中绘制图元的两种方式

DirectX 中绘制图元有两种类型的函数,一个是DrawPrimitiveUp,一个是DrawPrimitive,当然跟索引相关的也有两个类似的函 数,一个DrawIndexedPrimitiveUp,一个是DrawIndexedPrimitive: HRESULT DrawPrimitiveUP( [in]  D3DPRIMITIVETYPE PrimitiveType, [in]  UINT PrimitiveCount, [in]  const void *pVertexStreamZe