前端 js 实现 表单表格的 打印和保存功能

文章介绍了如何利用html2canvas和jspdf库在Vue应用中实现网页区域的打印和保存为PDF的功能。首先通过npm安装所需库,然后在utils文件夹下创建savepdf.js进行功能封装,包括滚动到页面顶部、生成canvas、转换为PDF等步骤。在Vue组件中引用预览组件并调用打印和保存方法完成操作。
摘要由CSDN通过智能技术生成

思路是: 利用我们的插件  html2canvas  和 jspdf ,然后把我们想要打印或者保存为PDF保存到本地的区域 作为一个参数 传入我们封装好的方法  去实现 打印和 保存功能 
 第一步:安装

npm i --save html2canvas jspdf

第二步 封装我们的打印和保存功能

我们可以在utils文件里 创建一个savepdf.js 文件 

import html2canvas from "html2canvas";
import jsPDF from "jspdf";

 function savePdf(node,title='log'){
        // 当下载pdf时,若不在页面顶部会造成PDF样式不对,所以先回到页面顶部再下载
        let top = node;
        if (top != null) {
          top.scrollIntoView();
          top = null;
        }
        html2canvas(node, {
          allowTaint: true,
        }).then(function (canvas) {
          const contentWidth = canvas.width;
          const contentHeight = canvas.height;
          //一页pdf显示html页面生成的canvas高度;
          let pageHeight = (contentWidth / 592.28) * 841.89;
          //未生成pdf的html页面高度
          let leftHeight = contentHeight;
          //页面偏移
          let position = 15;
          //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
          let imgWidth = 595.28;
          let imgHeight = (592.28 / contentWidth) * contentHeight;
          let pageData = canvas.toDataURL("image/jpeg", 1.0);
          const PDF = new jsPDF("", "pt", "a4");
          //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
          //当内容未超过pdf一页显示的范围,无需分页
          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();
              }
            }
          }
          // 下面的代码 是适合固定尺寸的 
          // const pageData = canvas.toDataURL("image/jpeg", 1.0);
          // //p表示纵向,l表示横向,px是单位 ,[宽,长]->[x,y]
          // const PDF = new JsPdf("p", "px", [2550, 3100]);
          // PDF.addImage(pageData, "JPEG", 0, 0, 2550, 3100);
          PDF.save(title + ".pdf");
        });
      
  
}

 function printTable(node){
    if (!node) {
      console.error('printArea is null');
      return;
    }
    let opts = {
        width: node.offsetWidth,
        height: node.offsetHeight,
        backgroundColor: "transparent",
        allowTaint: true
    }
    console.log(node)
    html2canvas(node,opts).then(canvas => {

     const iframe = document.createElement('iframe');
     iframe.style.display = 'none';
     document.body.appendChild(iframe);
      const content = node.innerHTML;
     const doc = iframe.contentDocument || iframe.contentWindow.document;
     doc.body.innerHTML = content;
     // 添加打印样式
     const style = doc.createElement('style');
     style.innerHTML = `
       @media print {
        @page {
            margin: 20px;
            size: auto;
            -webkit-print-color-adjust: exact;
          }
         html, body {
           margin: 0;
           padding: 20px;
         }
         img {
            border: none;
          }
          h1{
            display: flex;
            justify-content: center;
            align-content: center;
          }
         
          * {
            -webkit-print-color-adjust: exact !important;
            background: transparent !important;
            // color: rgba(0, 0, 0, 1) !important;
            text-shadow: none !important;
            box-shadow: none !important;
          }
          .no-print {
            display: none !important;
          }
        .page-break {
          page-break-before: always;
        }
        table {
            text-align: center;
            border-spacing: 0.5em; /* 设置表格行间距 */
            border-collapse: collapse; /* 合并表格边框 */
          }
          th, td {
            border: solid 1px black; /* 设置表格边框 */
            padding: 0.5em; /* 设置单元格内边距 */
          }
       }
     `;
     doc.head.appendChild(style);
      // 打印iframe
      iframe.contentWindow.focus();
      iframe.contentWindow.print();
      // 移除iframe
      document.body.removeChild(iframe);
    })
 }

 //第二种打印方法
//  function printTable(node){
//     if (!node) {
//       console.error('printArea is null');
//       return;
//     }
//     let opts = {
//         width: node.offsetWidth,
//         height: node.offsetHeight,
//         backgroundColor: "transparent",
//         allowTaint: true
//     }
//     console.log(node)
//     html2canvas(node,opts).then(canvas => {
//         let oImg = new Image(opts.width, opts.height);
//         oImg.src = canvas.toDataURL("image/jpeg", 1.0);  // 导出图片
//       const printDiv = document.createElement('div');

//       printDiv.appendChild(oImg);
//       const printWindow = window.open();
//       printWindow.document.write(printDiv.innerHTML);
//      return printWindow

//     })
//     .then( printWindow => {
//           printWindow.document.close();
//              printWindow.focus();
//           printWindow.print();
//           printWindow.close();
//     } )
//  }


export {
    savePdf,
    printTable,
   
  };

然后在vue文件中 我们需要用到的地方引入就可以了 

我们可以写一个弹框  把pre-view文件(需要打印的内容)引用过来  

per-viwe文件:

<template>
    <div class="reportForm">
        <div class="header">
            <h1>
                network monitoring report
            </h1>
        </div>
        <div class="reportInfo">
                <p>title: {{ reportInfo.title }} </p>
                <p>create date: {{  reportInfo.createTime }}</p>
                <p>collection period: {{ reportInfo.startDate }} - {{ reportInfo.endDate }} </p>
                <p>Author: {{ reportInfo.owner }}</p>
        </div>
        <div class="logData">
           <p>    {{ logType }}    </p> 
           <el-table
               :data="logData"
               style="width: 100%"
               :border="true"
               :highlight-current-row="true"
               :header-row-style="headerStyle"
           >
            <el-table-column
                    type="index"
                    label="No"
                    width="180">
                </el-table-column>
                <el-table-column
                    prop="date"
                    label="Date"
                    width="180">
                </el-table-column>
                <el-table-column
                    prop="message"
                    label="Message">
                </el-table-column>    
           </el-table>
        </div>
    </div>
</template>

<script>
    export default {
        name:'preview',
        props: {
            reportInfo:{
                type: Object,
                default:{}
            },
            logType:{
                type:String,
                default:'operation log'
            },
            logData:{
                type:Array,
                default: ()=> [],
                validator: (value) => {
                for (let i = 0; i < value.length; i++) {
                    const obj = value[i];
                    if (
                    !obj.date ||
                    typeof obj.date !== "string" ||
                    !obj.message ||
                    typeof obj.message !== "string"
                    ) {
                    return false;
                    }
                }
                return true;
                }
            }
        },
        data() {
            return {
                headerStyle: {
                     color:'black',
                     fontWeight: 'bolder'
                    }
                }
        }
    }
</script>

<style lang="scss" scoped>
.reportForm{
    margin: 0px 30px;
}
.reportInfo{
    display: flex;
    flex-direction: column;
    justify-content: start;
    align-items: flex-start;
    margin: 20px 0px;
}
.logData p{
    display: flex;
    padding: 10px 0px;
}

.el-table thead{
    color: black !important;
    font-weight: bolder !important;
}
</style>

在我们需要的页面 引入 这个预览组件  然后点击打印或者 保存功能   记得去 utils 文件引用过来

<el-dialog :visible.sync="formShow">
            <pre-view :reportInfo="previewDate" :logType="logType" :logData="logData" v-if="Object.keys(logData).length > 0"
                ref="printArea" id="printArea">
            </pre-view>
            <span slot="footer" class="dialog-footer">
                <el-button type="primary" @click="printFn">打印</el-button>
                <el-button type="primary" @click="saveFn">{{ $t('message.save') }}</el-button>
            </span>
        </el-dialog>

方法实现:

    printFn() {
        
  printTable(document.getElementById('printArea'))
},

 
        saveFn(){
                let content = document.getElementById('printArea');
                savePdf(content,'log')
        }

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值