La página frontal de Vue se da cuenta de la impresión y conversión de páginas a la descarga de PDF

La página frontal de vue realiza la impresión y conversión de la página a descarga PDF:
primero es una página de contrato, la función requerida es imprimir el contrato directamente en la página, o descargar el contrato en formato PDF: parte inferior de la
inserte la descripción de la imagen aquí
página:
inserte la descripción de la imagen aquí
primera impresión :
La función doPrint se llama:

doPrint() {
    
    
      this.$print(this.$refs.print);
    }

Defina print.js en utils:
inserte la descripción de la imagen aquí

// 打印类属性、方法定义
/* 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>";

      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')
              }
            }
          }
        }
      }
      // 包裹要打印的元素
      // fix: https://github.com/xyl66/vuePlugs_printjs/issues/36
      let outerHTML = this.wrapperRefDom(this.dom).outerHTML
      return outerHTML;
    },
    // 向父级元素循环,包裹当前需要打印的元素
    // 防止根级别开头的 css 选择器不生效
    wrapperRefDom: function (refDom) {
    
    
      let prevDom = null
      let currDom = refDom
      // 判断当前元素是否在 body 中,不在文档中则直接返回该节点
      if (!this.isInBody(currDom)) return currDom

      while (currDom) {
    
    
        if (prevDom) {
    
    
          let element = currDom.cloneNode(false)
          element.appendChild(prevDom)
          prevDom = element
        } else {
    
    
          prevDom = currDom.cloneNode(true)
        }

        currDom = currDom.parentElement
      }

      return prevDom
    },

    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);
      }
    },
    // 检查一个元素是否是 body 元素的后代元素且非 body 元素本身
    isInBody: function (node) {
    
    
      return (node === document.body) ? false : document.body.contains(node);
    },
    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

Agrega el siguiente código al estilo:
inserte la descripción de la imagen aquí

@media print {
    
    
  //重要
  /deep/ #app .content-container {
    
    
    width: 100% !important;
    // height: 100% !important;
    padding: 0 !important;
    // margin: 0 !important;
    margin-left: 0px !important;
  }
  //重要
  /deep/ #app .main-container {
    
    
    width: 100% !important;
    height: 100% !important;
    padding: 0 !important;
    margin: 0 !important;
  }
}
.pagehead {
    
    
  width: 100%;
  overflow: hidden;
}
.titleimg {
    
    
  height: 42px;
  width: 100%;
  margin-bottom: 0px;
}

/deep/ .el-radio__input.is-disabled + span.el-radio__label {
    
    
  color: #000 !important;
  font-weight: bold !important;
  font-size: 16px !important;
  padding-left: 3px !important;
}
.paper {
    
    
  padding-bottom: 60px;
}
.btnbox {
    
    
  width: calc(100vw - 180px);
  position: fixed;
  bottom: 0;
  right: 0;
  height: 60px;
  background-color: #fff;
  box-shadow: 1px 3px 9px rgba($color: #000000, $alpha: 0.2);
  background-color: #fff;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}
/deep/.el-image {
    
    
  width: 100px;
  height: 100px;
}
.dialog-footer {
    
    
  padding-top: 20px;
  text-align: center;
  color: #000000;
}
.el-form-item {
    
    
  display: inline-block;
  width: 40%;
  margin-bottom: 5px;
}

.contract-box {
    
    
  font-family: SimSun;
  line-height: 1.6;
  color: #000;
  font-weight: bold;
  text-align: center;
  margin: 10px auto;
  padding: 2% 23mm;
  div {
    
    
    margin-bottom: 10px;
  }
  .xiahuaxian {
    
    
    border-bottom: 1px solid #333;
    padding: 0 10px;
  }
  .space {
    
    
    padding-left: 30px;
  }

  .header {
    
    
    font-weight: 500;

    .title {
    
    
      font-weight: bold;
      font-family: SimSun;
      color: #000;
      font-size: 24px;
    }
    .sub-title {
    
    
      font-weight: bold;
      font-family: SimSun;
      color: #000;
      font-size: 22px;
      padding-top: 10px;
    }
  }
  .center {
    
    
    // padding-top: 10px;
    font-weight: 500;
    font-size: 16px;
    text-align: left;
    color: #000;
    // font-weight: bold;
  }
  .content {
    
    
    font-weight: 500;
    font-size: 16px;
    text-align: left;
    color: #000;
    font-weight: bold;
    text-indent: 2em;
    margin-bottom: 10px;
    text-indent: 40px;
  }
}
/deep/ .el-radio__input.is-disabled + span.el-radio__label {
    
    
  color: #333;
}
/deep/ .el-radio__input.is-disabled.is-checked .el-radio__inner {
    
    
  background-color: #ffffff;
  border-color: #9c9c9c;
}
/deep/ .el-radio__input.is-disabled .el-radio__inner {
    
    
  background-color: #ffffff;
  border-color: #9c9c9c;
}
/deep/ .el-radio__input.is-disabled.is-checked .el-radio__inner::after {
    
    
  background-color: #7e8ba5;
}
.mytable {
    
    
  width: 100%;
  text-align: center;
  border-collapse: collapse;
  .mytd {
    
    
    // padding: 10px 0;
    height: 34px;
    .inner-div {
    
    
      text-align: left;
      padding-top: 5px;
      padding-left: 5px;
    }
  }
}
.sign-box {
    
    
  display: flex;
  align-items: flex-start;
  .sign-item {
    
    
    width: 50%;
    display: flex;
    justify-content: flex-start;
    align-items: flex-end;
  }
}
.sheet {
    
    
  -webkit-box-shadow: 0 0.5mm 2mm rgb(255, 255, 255);
  box-shadow: 0 0.5mm 2mm rgba(0, 0, 0, 0);
}

Introducido y utilizado en main.js: import Print from './utils/print.js' Vue.use(Print)
inserte la descripción de la imagen aquí
impresión de prueba:
inserte la descripción de la imagen aquí

2. Descargar:
Defina htmlToPdf.js en utils:

// 导出页面为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");
      });
    };
  }
};

Llamado en main.js:import htmlToPdf from './utils/htmlToPdf.js' Vue.use(htmlToPdf)
inserte la descripción de la imagen aquí

Después de guardar aquí, la página informará un error: no se puede encontrar el módulo jspdf

These dependencies were not found:

* html2canvas in ./src/utils/htmlToPdf.js
* jspdf in ./src/utils/htmlToPdf.js

To install them, you can run: npm install --save html2canvas jspdf

Instale el módulo:cnpm install [email protected]
inserte la descripción de la imagen aquí

Descarga de prueba:
inserte la descripción de la imagen aquí

El archivo css introducido por la página se colocó en el disco de la nube: Enlace: https://pan.baidu.com/s/1iNj8Z1Wk4JiaiCXHfNXR4w?pwd=6666 Código de extracción: 6666 Después de copiar este contenido, abra la aplicación móvil Baidu Netdisk, que es más conveniente para operar oh
inserte la descripción de la imagen aquí

El código de la plantilla para la página del contrato es el siguiente:

<template>
  <div style="  background-color: #fff;">
    <!-- <el-breadcrumb
      separator-class="el-icon-arrow-right"
      style="margin: 0 5px 5px 5px"
    >
      <el-breadcrumb-item :to="{ path: 'contract' }"
        >合同列表</el-breadcrumb-item
      >
      <el-breadcrumb-item>合同详情</el-breadcrumb-item>
    </el-breadcrumb> -->
    <div class="paper A4" style="margin:0 auto;background-color: #fff;">
      <div class="contract-box sheet" ref="print" id="pdfDom">
        <div class="header">
          <!-- <div class="pagehead" style="margin-bottom: 0">
            <el-image
       class="titleimg"
      :src="contractInfo.logo"></el-image>

          </div> -->
          <div class="title" style="margin-bottom: 0">
            {
    
    {
    
     contractInfo.title }}
          </div>

          <!-- <div class="sub-title" style="margin-bottom: 0">工程业务合约</div> -->
        </div>
        <div class="center">
          <div>
              <span>  甲方单位名称:</span>
              <span class="xiahuaxian"
                >{
    
    {
    
     contractInfo.partya }}</span>
              <span class="space"></span>
               <span>  甲方代表:</span>
              <span class="xiahuaxian"
                >{
    
    {
    
     contractInfo.partyaDelegate }}</span>
              <span class="space"></span>
              <span>  甲方代表联系方式:</span>
              <span class="xiahuaxian">{
    
    {
    
     contractInfo.partyaMobile }}</span>
              <span class="space"></span>
              <span>  甲方公司地址:</span>
              <span class="xiahuaxian">{
    
    {
    
    contractInfo.partyaAddress }}</span>
               <!-- <span class="space"></span>
              <span>  甲方项目经理:</span>
              <span class="xiahuaxian">{
    
    {
    
     contractInfo.siteManager }}</span>
              <span class="space"></span>
              <span>  联系方式:</span>
              <span class="xiahuaxian">{
    
    {
    
     contractInfo.siteManagerMobile }}</span> -->
            </div>
            <div>
               <span>  乙方单位名称:</span>
              <span class="xiahuaxian"
                >{
    
    {
    
     contractInfo.partyb }}</span>
              <span class="space"></span>
              <span>  乙方代表:</span>
              <span class="xiahuaxian"
                >{
    
    {
    
     contractInfo.partybDelegate }}</span>
              <span class="space"></span>
              <span>  乙方代表联系方式:</span>
              <span class="xiahuaxian">{
    
    {
    
     contractInfo.partybMobile }}</span>
               <span class="space"></span>
              <span>  乙方公司地址:</span>
              <span class="xiahuaxian">{
    
    {
    
     contractInfo.partybAddress }}</span>
              <!-- <span class="space"></span>
              <span> 经理联系方式:</span>
              <span class="xiahuaxian">{
    
    {
    
     contractInfo.partybManagerMobile }}</span> -->
            </div>
          <div class="content">
            {
    
    {
    
     contractInfo.content }}
          </div>

          <div>
            <div>
              <!-- <span>工程项目地址:</span>
              <span class="xiahuaxian"
                >{
    
    {
    
     contractInfo.province }}{
    
    {
    
     contractInfo.city
                }}{
    
    {
    
     contractInfo.region
                }}{
    
    {
    
     contractInfo.detailAddress }}</span
              > -->
              <span class="space"></span>
              <span>约定服务工期:</span>
              <span class="xiahuaxian"
                >{
    
    {
    
     contractInfo.startTime }}{
    
    {
    
    
                  contractInfo.finishTime
                }}</span
              >
            </div>
            <div>
              包工:工程项目总额:<span class="xiahuaxian">
                {
    
    {
    
     contractInfo.totalMoney }} </span
              ><span class="space"></span>
              定金及预付款:<span class="xiahuaxian">
                {
    
    {
    
     contractInfo.frontMoney }}</span
              ><span class="space"></span>
              项目尾款:<span class="xiahuaxian">{
    
    {
    
    
                contractInfo.finishMoney
              }}</span
              ></div>
            <!-- <div>
              点工:<span class="xiahuaxian">{
    
    {
    
    
                contractInfo.spotWorkWages
              }}</span
              >/<span class="space"></span>
              约定服务时间:<span class="xiahuaxian"
                >{
    
    {
    
     contractInfo.appointmentStartTime }}{
    
    {
    
    
                  contractInfo.appointmentEndTime
                }}</span
              >
              <span class="space"></span>
              约定加班费:<span class="xiahuaxian">{
    
    {
    
    
                contractInfo.appointmentWorkOvertime
              }}</span>
              <span class="space"></span>
            </div> -->
            <!-- <div>
              付款渠道:
              <el-radio
                :label="1"
                v-model="isCheck"
                :disabled="true"
                style="color: #000; font-weight: bold; font-size: 16px"
                >微信</el-radio
              >
              <el-radio
                :label="2"
                v-model="isCheck"
                :disabled="true"
                style="color: #000; font-weight: bold"
                >支付宝</el-radio
              >
              <el-radio
                :label="3"
                v-model="isCheck"
                :disabled="true"
                style="color: #000; font-weight: bold"
                >银行转账</el-radio
              >
              <el-radio
                :label="4"
                v-model="isCheck"
                :disabled="true"
                style="color: #000; font-weight: bold"
                >现金</el-radio
              >
              <el-radio
                :label="5"
                v-model="isCheck"
                :disabled="true"
                style="color: #000; font-weight: bold"
                >其他</el-radio
              >
              约定付款时间:<span class="xiahuaxian"></span>
            </div> -->
            <!-- <div>工程服务明细及要求:</div>
            <div>
              <table border="1" class="mytable">
                <tr v-if="otherContractProofing.length>0">
                  <td class="mytd" colspan="1">名称</td>
                  <td class="mytd" colspan="1">数量</td>
                  <td class="mytd" colspan="1">单价</td>
                  <td class="mytd" colspan="1">总价</td>
                </tr>
                <tr >
                  <td class="mytd" colspan="1">{
    
    {
    
     contractProofing.name }}</td>
                  <td class="mytd" colspan="1">{
    
    {
    
     contractProofing.num }}</td>
                  <td class="mytd" colspan="1">{
    
    {
    
     contractProofing.price }}</td>
                  <td class="mytd" colspan="1">
                    {
    
    {
    
     contractProofing.totalPrice }}
                  </td>
                </tr>
                <tr v-for="(item, index) in otherContractProofing" :key="index"  v-if="otherContractProofing.length>0">
                  <td class="mytd" colspan="1">{
    
    {
    
     item.name }}</td>
                  <td class="mytd" colspan="1">{
    
    {
    
     item.num }}</td>
                  <td class="mytd" colspan="1">{
    
    {
    
     item.price }}</td>
                  <td class="mytd" colspan="1">{
    
    {
    
     item.totalPrice }}</td>
                </tr>


                <tr  v-if="otherContractProofing.length>0">
                  <td class="mytd">合计:</td>
                  <td class="mytd">{
    
    {
    
     total.num }}</td>
                  <td class="mytd">{
    
    {
    
     total.price }}</td>
                  <td class="mytd">{
    
    {
    
     total.totalPrice }}</td>
                </tr>
                <tr>
                  <td class="mytd" colspan="5">
                    <div class="inner-div">
                      特殊注意事项:{
    
    {
    
     contractInfo.specialNotes }}
                    </div>
                  </td>
                </tr>
                <tr>
                  <td class="mytd" colspan="5">
                    <div class="inner-div">
                      约定服务质量及施工要求{
    
    {
    
     contractInfo.quality}}
                    </div>
                  </td>
                </tr>
              </table>
            </div> -->
            <div>
              合约备注:<br />
              {
    
    {
    
     contractInfo.remarks }}
            </div>
            <!-- <div>
              合约备注:
              <br />
              1.本合约一式三份,甲方持一份,乙方两份,以甲方签字,乙方签字盖章生效。
              <br />
              2.如有任何合约变动,需经双方协商,书面补充该协议,口头协议视为无效。
            </div> -->
            <div style="height: 1px"></div>
             <div class="sign-box" style="margin-bottom: 0px">
               <div class="sign-item" style="margin-bottom: 0">
                <span>甲方签名:</span>
               <!-- <img style="width:60px;height:60px" src="" alt=""> -->
              </div>
              <div class="sign-item" style="margin-bottom: 0">
                <span>乙方签名:</span>
               <!-- <img style="width:60px;height:60px" src="" alt=""> -->
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

  </div>
</template>

Supongo que te gusta

Origin blog.csdn.net/weixin_42260782/article/details/127745837
Recomendado
Clasificación