vue uses printJs to implement front-end printing and print paging implementation

On the web side, you can directly use the native calling method to call printing, but you often need to pull out the things that need to be printed and draw a separate html. With printJs, you can select the code block you need to print and print part of the page.

My requirement is to print out the form and display it in pagination if the number of pagination is exceeded.

The following content refers to the implementation methods of other bloggers and is for reference only.

Realize printing

1. You can directly use the following code to generate a js file in the project and reference it globally in main.js. The following code uses PrintJS for Vue to implement the page printing function_this.$print_Dai Xiaojie's Blog-CSDN Blog

The modified code by blogger Dai Xiaojie can also be downloaded and referenced using npm.

/**
* 打印类属性、方法定义,需要先在插件中引入
* 使用示例: 1. 先在mian.js中引入
*          2. 函数中调用this.$print(this.$refs.xxxx)
*/

/* 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>";
   //这边样式要谨慎使用,会覆盖样式表中设置的样式  -->按照自己的业务需求拼接,会覆盖外面H5原先的样式
   str += "<style>html,body,div{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

Write according to the method provided by the blogger

Bind ref and use this.$print(this.$refs.xxx) to print out the elements you need in this code block.

  • If elements that do not need to be printed are added  class="no-print", elements with such names will be ignored when printing.

You can refer to the blogger’s modified js for this piece.

Implement paging

What I use here is el-dialog to draw the print preview display I need. If you don’t need to preview the page display, you can hide the elements from the code. As for the method, you can explore it yourself, such as position:absolute, top:100000px, or other false In the deletion method, do not use v-if and other real deletions. After the node is deleted, the ref cannot be obtained and cannot be printed.

getPrintDataInfo(data) {
      const arrCopy = JSON.parse(JSON.stringify(data))
      arrCopy.forEach((items, indexs) => {
        items.printTime = this.$moment().format('YYYY-MM-DD HH:ss:mm')//这里是我的需要的打印时间
        if (items.list.length % this.page.size === 0) {
          this.totalPage = items.list.length / this.page.size//this.page.size是我列表的分页显示条数,这边使用为打印时一个页面的条数
        } else {
          this.totalPage = parseInt(items.list.length / this.page.size) + 1
        }
        for (let i = 1; i <= this.totalPage; i++) {
          const obj = JSON.parse(JSON.stringify(items))
          obj.list = this.getTableDataByPaging(i, this.page.size, items.list).data
          obj.currentPage = this.getTableDataByPaging(i, this.page.size, items.list).page
          this.dataList.push(obj)
        }
      })
    },
    // 打印清单分页数据处理
    getTableDataByPaging(page = 1, pageSize = 10, totalData = []) {
      const { length } = totalData
      const tableData = {
        data: [],
        page,
        pageSize,
        length
      }
      if (pageSize >= length) { // pageSize大于等于总数据长度,说明只有1页数据或没有数据
        tableData.data = totalData
        tableData.page = 1// 直接取第一页
      } else { // pageSize小于总数据长度,数据多余1页
        const num = pageSize * (page - 1)// 计算当前页(不含)之前的所有数据总条数
        if (num < length) { // 如果当前页之前所有数据总条数小于(不能等于)总的数据集长度,则说明当前页码没有超出最大页码
          const startIndex = num// 当前页第一条数据在总数据集中的索引
          const endIndex = num + pageSize - 1// 当前页最后一条数据索引
          tableData.data = totalData.filter((_, index) => index >= startIndex && index <= endIndex)// 当前页数据条数小于每页最大条数时,也按最大条数范围筛取数据
        } else { // 当前页码超出最大页码,则计算实际最后一页的page,自动返回最后一页数据
          const size = parseInt(length / pageSize) // 取商
          const rest = length % pageSize // 取余数
          if (rest > 0) { // 余数大于0,说明实际最后一页数据不足pageSize,应该取size+1为最后一条的页码
            tableData.page = size + 1// 当前页码重置,取size+1
            tableData.data = totalData.filter((_, index) => index >= (pageSize * size) && index <= length)
          } else if (rest === 0) { // 余数等于0,最后一页数据条数正好是pageSize
            tableData.page = size// 当前页码重置,取size
            tableData.data = totalData.filter((_, index) => index >= (pageSize * (size - 1)) && index <= length)
          } // 注:余数不可能小于0
        }
      }
      return tableData
    },

v-for loop on page

<div ref="printLend" class="pitchman-box ">
          <div v-for="(item,indexs) in dataList" :key="indexs" class="printClass" style="page-break-after: always;">
            <el-row>
              <h2>{
   
   { item.title }}</h2>
            </el-row>
            <el-row class="print_info">
              <el-col :span="6"><span>借出人:</span>{
   
   { item.name }}</el-col>
              <el-col :span="6"><span>联系方式:</span>{
   
   { item.phone }}</el-col>
              <el-col :span="6"><span>借出时间:</span>{
   
   { item.lendTime }}</el-col>
              <el-col :span="6"><span>押金:</span>{
   
   { item.price }}</el-col>
            </el-row>
            <table border="1" width="100%" height="100%" cellspacing="0" cellpadding="0">
              <thead>
                <!--表头,这里就是正常的表格循环-->
                <th>序号</th>
              </thead>
              <tbody align="center">
                <tr v-for="(items,index) in item.list" :key="index">
                  <td>{
   
   { index +1 }}</td>
                </tr>
              </tbody>
            </table>
            <el-row class="logistics-bottom">
              <el-col style="text-align: left;" :span="12">打印时间:{
   
   { item.printTime }}</el-col>
              <el-col style="text-align: right;" :span="12">第{
   
   { item.currentPage }}页,共{
   
   { totalPage }}页</el-col>
            </el-row>
            <!-- <div style="page-break-after: always;" /> -->
          </div>

style="page-break-after: always;"Add this style attribute where you need to break the next page to print.

 

This is my final preview. The effect is perfect when printed on A4 paper. A title is a piece of paper.

It is worth noting that it is not recommended to set the height of the entire printing element you need beyond hiding and displaying the scroll bar. You can decide how to implement it in terms of style. Generally, the printed effect will not be much different.

 The general code implementation is like this. If there are any mistakes, please correct me. If you have a better implementation method, you can also share it. If you have a better way to achieve the fluid height when previewing the table, please let me know. Thank you!!!

Guess you like

Origin blog.csdn.net/Arcobaleno_1177/article/details/132159680