美文网首页
前端实现HTML转PDF下载

前端实现HTML转PDF下载

作者: 萤火kin | 来源:发表于2021-07-28 14:12 被阅读0次

    参考https://www.jianshu.com/p/56680ce1cc97

    使用html2canvas和jspdf插件实现

    该方式是通过html2canvas将HTML页面转换成图片,然后再通过jspdf将图片的base64生成为pdf文件。实现步骤如下:

    1,下载插件模块

    npm install html2canvas jspdf --save
    

    2,定义功能实现方法

    在项目工具方法存放文件夹utils中创建htmlToPdf.js文件,代码如下:

    // 导出页面为PDF格式
    import html2Canvas from 'html2canvas'
    import JsPDF from 'jspdf'
    export default{
      install (Vue, options) {
        Vue.prototype.getPdf = function () {
          var title = this.htmlTitle
          html2Canvas(document.querySelector('#pdfDom'), {
            allowTaint: true
          }).then(function (canvas) {
            let contentWidth = canvas.width
            let contentHeight = canvas.height
            let pageHeight = contentWidth / 592.28 * 841.89
            let leftHeight = contentHeight
            let position = 0
            let imgWidth = 595.28
            let imgHeight = 592.28 / contentWidth * contentHeight
            let pageData = canvas.toDataURL('image/jpeg', 1.0)
            let PDF = new JsPDF('', 'pt', 'a4')
            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()
                }
              }
            }
            PDF.save(title + '.pdf')
          }
          )
        }
      }
    }
    

    3, 全局引入实现方法

    在项目主文件main.js中引入定义好的实现方法,并注册。

    import htmlToPdf from '@/components/utils/htmlToPdf'
    // 使用Vue.use()方法就会调用工具方法中的install方法
    Vue.use(htmlToPdf)
    

    4,在相关要导出的页面中,点击时调用绑定在Vue原型上的getPdf方法,传入id即可

    参考

    //html
     <div id="pdfDom">
       <!-- 要下载的HTML页面,页面是由后台返回 -->
      <div v-html="pageData"></div>
    </div>
    <el-button type="primary" size="small" @click="getPdf('#pdfDom')">点击下载</el-button>
    
    //js
    export default {
      data () {
          return {
          htmlTitle: '页面导出PDF文件名'
          }
      }
     }
    

    实际运用

    • voucherPdf 为PDF页面组件。
    • 要下载的PDF内容要在页面展示出来,所以用了弹窗预览的方式,如果用v-if或v-show等方式将要下载的html隐藏起来,会造成下载出来的PDF是空白。
    • 另外下载下来的pdf会根据html的大小进行放大和缩小,所以弹窗的宽高及字体的大小等要自己的情况酌情调整。
    <!-- 下载凭证 -->
    <Modal v-model="hasPDFModal"
        title="下载凭证预览">
        <voucherPdf :voucherInfo="voucherInfo" id="pdfDom"/>
        <div slot="footer">
            <Button @click="hasPDFModal = false;">取消</Button>
            <Button @click="getPdf('#pdfDom');hasPDFModal = false;" type="primary">下载</Button>
        </div>
    </Modal>
    import voucherPdf from "_c/voucher-pdf/voucherPdf.vue"
    export default {
    components: {
            voucherPdf
        },
      data () {
          return {
          htmlTitle: '页面导出PDF文件名',
          hasPDFModal: false,
          voucherInfo: {
                    orderCreateTime: "",
                    channelFullName: "",
                    id: "",
                    orderDate: "",
                    channelOrderId: "",
                    merchantUserName: "",
                    merchantUserPhone: "",
                    merchantUserEmail: "",
                    orderAmount: "",
                    amount: "",
                    paytypeName: "",
                    email: "",
                },
          }
      }
     }
    

    PDF组件文件

    <template>
        <div class="voucherPdf">
            <h3>INVOICE # {{ voucherInfo.orderCreateTime }}</h3>
            <div class="title">{{ voucherInfo.channelFullName }}</div>
            <div class="body">
                <div class="orderInfo">
                    <div class="orderInfoLeft">
                        <span>Order Number:</span>
                        <span>Order Date:</span>
                        <span>Transaction Order ID:</span>
                    </div>
                    <div class="orderInfoRight">
                        <span>{{ voucherInfo.id }}</span>
                        <span>{{ voucherInfo.orderDate }}</span>
                        <span>{{ voucherInfo.channelOrderId }}</span>
                    </div>
                </div>
                <div class="merchantBoth merchantBothTitle">
                    <span class="merchantBothLeft">BILLTO</span>
                    <span class="merchantBothRight">FOR</span>
                </div>
                <div class="merchantBoth">
                    <span class="merchantBothLeft"
                        >Customer Name / User ID:
                        {{ voucherInfo.merchantUserName }}</span
                    >
                    <span class="merchantBothRight">Wallet Deposit/Recharge</span>
                </div>
                <div class="merchantOnly">
                    Mobile No: {{ voucherInfo.merchantUserPhone }}
                </div>
                <div class="merchantOnly">
                    Email IPayer's Email: {{ voucherInfo.merchantUserEmail }}
                </div>
                <div class="dealBoth">
                    <span class="dealBothLeft">Details</span>
                    <span class="dealBothRight">AMOUNT</span>
                </div>
                <div class="dealBoth">
                    <span class="dealBothLeft">Wallet Deposit/Recharge</span>
                    <span class="dealBothRight">{{ voucherInfo.orderAmount }}</span>
                </div>
                <div class="midTop"></div>
                <div class="midBottom"></div>
                <div class="amountBoth">
                    <span class="amountBothLeft">SUBTOTAL:</span>
                    <span class="amountBothMid"></span>
                    <span class="amountBothRight">{{
                        voucherInfo.orderAmount
                    }}</span>
                </div>
                <div class="amountBoth">
                    <span class="amountBothLeft">Includes GST:</span>
                    <span class="amountBothMid"></span>
                    <span class="amountBothRight">0.00%</span>
                </div>
                <div class="amountBoth">
                    <span class="amountBothLeft">TOTAL:</span>
                    <span class="amountBothMid"></span>
                    <span class="amountBothRight">{{
                        voucherInfo.orderAmount
                    }}</span>
                </div>
                <div class="paymentBoth">
                    <span class="paymentBothLeft">Payment method:</span>
                    <span class="paymentBothRight"
                        >{{ voucherInfo.paytypeName }}({{
                            voucherInfo.merchantUserEmail
                        }})</span
                    >
                </div>
                <div class="remarks">
                    If you have any questions concerning this invoice, use the
                    following contact infomation;
                </div>
                <div class="remarks">Email id: {{ voucherInfo.email }}</div>
                <div class="bottomTips">
                    * This is an auto-generaled email. Please do not reply to this
                    email. *
                </div>
            </div>
        </div>
    </template>
    <script>
    export default {
        name: "voucherPdf",
        props: {
            voucherInfo: {
                type: Object,
                default: {
                    orderCreateTime: "",
                    channelFullName: "",
                    id: "",
                    orderDate: "",
                    channelOrderId: "",
                    merchantUserName: "",
                    merchantUserPhone: "",
                    merchantUserEmail: "",
                    orderAmount: "",
                    amount: "",
                    paytypeName: "",
                    email: "",
                },
            },
        },
        data() {
            return {};
        },
        mounted() {},
        methods: {},
    };
    </script>
    <style lang="less" scoped>
    .voucherPdf {
        width: 100%;
        display: flex;
        align-items: center;
        flex-direction: column;
        padding: 20px 0 20px;
        font-size: 14px;
        word-wrap: break-word;
        h3 {
            font-size: 14px;
        }
        .title {
            height: 50px;
            width: 100%;
            background: olive;
            color: #fff;
            font-size: 18px;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .body {
            width: 100%;
            padding: 0 3% 0;
            .orderInfo {
                width: 100%;
                display: flex;
                justify-content: space-between;
                padding: 10px 0 10px;
            }
            .orderInfoLeft,
            .orderInfoRight {
                width: 50%;
                display: inline-block;
                display: flex;
                align-items: center;
                flex-direction: column;
            }
            .merchantBoth {
                width: 100%;
                display: flex;
                .merchantBothLeft {
                    width: 60%;
                    display: inline-block;
                }
                .merchantBothRight {
                    width: 40%;
                    display: inline-block;
                }
            }
            .merchantBothTitle {
                font-size: 18px;
                color: rgb(212, 199, 174);
            }
            .merchantOnly {
                width: 100%;
            }
            .dealBoth {
                width: 100%;
                padding: 5px 0 0;
                font-weight: 800;
                display: flex;
                // align-items: center;
                .dealBothLeft {
                    width: 60%;
                    display: inline-block;
                }
                .dealBothRight {
                    width: 40%;
                    display: inline-block;
                    text-align: center;
                }
            }
            .amountBoth {
                width: 100%;
                padding: 5px 0 0;
                font-weight: 600;
                display: flex;
                .amountBothLeft {
                    width: 50%;
                    display: inline-block;
                    text-align: right;
                }
                .amountBothMid {
                    width: 10%;
                }
                .amountBothRight {
                    width: 40%;
                    display: inline-block;
                    text-align: center;
                }
            }
            .paymentBoth {
                width: 100%;
                padding: 5px 0 0;
                font-weight: 800;
                display: flex;
                .paymentBothLeft {
                    width: 40%;
                    display: inline-block;
                }
                .paymentBothRight {
                    width: 60%;
                    display: inline-block;
                }
            }
            .midTop {
                border-top: 1px solid green;
                width: 100%;
                height: 30px;
            }
            .midBottom {
                border-top: 1px solid green;
                border-bottom: 1px solid green;
                width: 100%;
                height: 30px;
            }
            .remarks {
                width: 100%;
                padding: 10px 0 0;
            }
            .bottomTips {
                width: 100%;
                padding-top: 40px;
                text-align: center;
            }
        }
    }
    </style>
    

    相关文章

      网友评论

          本文标题:前端实现HTML转PDF下载

          本文链接:https://www.haomeiwen.com/subject/rzgxvltx.html