「VUE」前端实现真正的无感打印(可打印dom、file、url) CSDN首发

功能

你好! 如果你是一名纯前端,那么阅读完这篇文章即可以解决无感打印的问题!
目前可以实现的功能有:

  1. 前端无任何弹窗直接调用打印机执行打印
  2. 打印pdf流、打印在线文件、调用斑马打印服务(斑马打印正在测试,已集成到当前版本,若要使用请留言)
  3. 设置纸张大小
  4. 可分页打印
  5. 输出打印日志
  6. 获取当前用户电脑外接的所有打印机
  7. 获取用户的默认打印机,同时可选择使用哪台打印机执行打印
  8. 附加功能:HTML转成pdf的file/blob流文件、生成分页pdf文件

说到前面

相信大家在搜到我的这篇文章前已经在网上搜索过大量前端无感打印的文章。

先谈谈目前前端常见的两种方法

  • 第一种 JS的print方法,这种方法一定会弹出打印预览窗,且如果需要打印页面内部分dom内容需要重新write页面等等弊端。
  • 第二种 LODOP(露肚皮)不得不说这是一款优秀的打印插件, 但是如果不买,打印出来有水印~

这篇文章如果教你使用以上两种方法,意义不大,论坛里有很多很棒的教程。 接下来你将接触到非常简单且免费(接下来会会考虑开源)的前端无感打印!

在这里先介绍VUE下无感打印的准备工作(其他框架原理一样的,最近比较忙,之后我会慢慢补充)

  • 插件我这里使用了html2canvas和jspdf
  • 安装我们开发的exe文件 点击下载 提取码: u582

准备工作

  • 安装依赖:npm install html2canvas jspdf --save
  • 新建一个html2pdf.js文件,代码见code 1 (有一些额外的功能好奇的可以逐行的取消下面的注释,看看效果)
  • 新建接口文件localPrint.js ,这里使用了axios,也可以使用原生,具体方法随你. 代码见code 2
  • 新建方法库pdf2Print.js,这里加载了之前的两个js文件。代码见code 3
  • 在mian.js中引入:import htmlToPdf from ‘…/XXX/html2pdf’(注意路径)
  • 在mian.js中引入:import dom2Print from ‘…/XXX/pdf2Print’(注意路径)

文件最好都放在同一文件夹下,这样可以省着你来改js里面的的引入路径。文件最好都放在同一文件夹下,这样可以省着你来改js里面的的引入路径。

这套东西写的比较粗糙, 后期我会提交到npm上方便大家更方便的使用。

code1:
// dom转pfd的file流
import html2canvas from 'html2canvas'
import JSPDF from 'jspdf'

export default {
  install (Vue, options) {
    Vue.prototype.ExportSavePdf = function (htmlTitle, currentTime, callBack) {
      const element = document.getElementById('pdfCentent')
      html2canvas(element, {
        logging: false
      }).then(function (canvas) {
        const pdf = new JSPDF('p', 'mm', 'a4') // A4纸,纵向
        const ctx = canvas.getContext('2d')
        const a4w = 210; const a4h = 297 // A4大小,210mm x 297mm,四边各保留20mm的边距,显示区域170x257
        const imgHeight = Math.floor(a4h * canvas.width / a4w) // 按A4显示比例换算一页图像的像素高度
        let renderedHeight = 0

        while (renderedHeight < canvas.height) {
          const page = document.createElement('canvas')
          page.width = canvas.width
          page.height = Math.min(imgHeight, canvas.height - renderedHeight)// 可能内容不足一页

          // 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
          page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0)
          pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 0, 0, a4w, Math.min(a4h, a4w * page.height / page.width)) // 添加图像到页面,保留10mm边距

          renderedHeight += imgHeight
          if (renderedHeight < canvas.height) { pdf.addPage() }// 如果后面还有内容,添加一个空页
          // delete page;
        }
        // pdf.save(htmlTitle + currentTime)
        // console.log(pdf.output('blob'), pdf.output(), 11111)
        // console.log(pdf.output(), 'blob对象')
        // console.log(new File([pdf.output()], htmlTitle + '.pdf'), 'file对象')
        const file = new File([pdf.output('blob')], htmlTitle + '.pdf')
        Vue.nextTick(() => {
          callBack(file)
        })
      })
    }
  }
}

code2:
import { axios } from '@/utils/request'

export function getPrinters (parameter) {
  return axios({
    url: 'http://127.0.0.1:20730/getPrinters?_m=' + Math.random(),
    method: 'get'
  })
}
export function getDefaultPrinter (parameter) {
  return axios({
    url: 'http://127.0.0.1:20730/getDefaultPrinter?_m=' + Math.random(),
    method: 'get'
  })
}

export function printPdf (parameter) {
  return axios({
    url: 'http://127.0.0.1:20730/printPdf?_m=' + Math.random(),
    method: 'post',
    data: parameter
  })
}

export function printZebra (parameter) {
  return axios({
    url: 'http://127.0.0.1:20730/printZebra?_m=' + Math.random(),
    method: 'post',
    data: parameter
  })
}
code3
/* eslint-disable no-unused-vars */
import htmlToPdf from './html2pdf'
import { getPrinters, getDefaultPrinter, printPdf, printZebra } from '@/api/localPrint'

console.log(htmlToPdf)
export default {
  install (Vue, options) {
    class Dom2Print {
      constructor () {
        this.name = 'dom2Pdf'
        this.contentData = {}
        this.alertFlag = false
      }
      onblur () {}
      onfocus () {}
      addAlertListen (startEvent, loadingEvent, connectionEvent, faildEvent, faild) {
        const that = this
        this.onblur = function () {
          console.log('sj')
          that.alertFlag = true
        }
        this.onfocus = function () {
          setTimeout(() => {
            console.log('jj')
            that.connectionState(startEvent, loadingEvent, connectionEvent, faildEvent)
          }, 2000)
        }
        getPrinters().then(res => {
          that.connectionState(startEvent, loadingEvent, connectionEvent, faildEvent)
        }).catch(() => {
          window.addEventListener('blur', that.onblur)
          window.addEventListener('focus', that.onfocus)
          const a = document.createElement('a')
          a.href = 'SLIENTPRINT://'
          a.click()
          setTimeout(() => {
            if (!that.alertFlag) {
              faild()
              window.removeEventListener('focus', that.onfocus)
              window.removeEventListener('blur', that.onblur)
            }
          }, 5000)
        })
      }
      // 调用斑马打印机
      printWithZebra (data, succe, err) {
        // data为对象 其余两参数为方法
        // 第一参数需要传的值
        // zebraCode    斑马zpl字符串
        // zebraPrinterIp    斑马打印机ip
        // zebraPrinterPort    斑马打印机端口
        // zebraPrinterName    斑马打印机名称
        if (data.zebraCode) {
          if (data.zebraPrinterIp) {
            if (data.zebraPrinterPort) {
              printZebra(data).then(res => {
                succe(res)
              }).catch(() => {
                err()
              })
            } else {
              console.error('若传zebraPrinterIp 那么zebraPrinterPort必传')
            }
          } else {
            if (data.zebraPrinterName) {
              printZebra(data).then(res => {
                succe(res)
              }).catch(() => {
                err()
              })
            } else {
              console.error('zebraPrinterIp + zebraPrinterPort 或者 zebraPrinterName 二组选一个 为必传')
            }
          }
        } else {
          console.error('zebraCode斑马zpl字符串 为必传')
        }
      }
      printDom (that, size, choosePrint, success, faild, url) {
        that.ExportSavePdf('油耗标pdf', '.pdf', (fileData) => {
          const formData = new FormData()
          formData.append('file', fileData)
          formData.append('copies', '1')
          formData.append('url', url || '')
          formData.append('paperSize', size)
          formData.append('printer', choosePrint)

          printPdf(formData).then(res => {
            if (res.result === 'success') {
              console.log('打印成功')
              success()
              // this.$message.success('打印成功', 3)
            } else if (res.result === 'failure') {
              console.log('打印失败')
              faild(1)
              // this.$message.error('打印失败', 3)
            } else if (res.result === 'unavailable') {
              console.log('服务未开启')
              faild(2)
              // this.$message.error('服务未开启', 3)
            }
          }).catch(() => {
            faild(3)
          })
        })
      }
      // 打印url
      printUrl (url, size, success, failed) {
        const formData = new FormData()
        formData.append('copies', 1)
        formData.append('duplex', false)
        formData.append('url', url)
        formData.append('paperSize', size || 'A4')

        printPdf(formData).then(res => {
          if (res.result === 'success') {
            console.log('打印成功')
            success()
            // this.$message.success('打印成功', 3)
          } else if (res.result === 'failure') {
            console.log('打印失败')
            failed(1)
            // this.$message.error('打印失败', 3)
          } else if (res.result === 'unavailable') {
            console.log('服务未开启')
            failed(2)
            // this.$message.error('服务未开启', 3)
          }
        }).catch(() => {
          failed(3)
        })
      }
      getPrintList (a) {
        getPrinters().then(res => {
          a(res)
        })
      }
      getDefaultPrint (a) {
        getDefaultPrinter().then(res => {
          a(res)
        })
      }
      openEXE (callBack) {
        const e = callBack || function () {}
        const a = document.createElement('a')
        a.href = 'SLIENTPRINT://'
        getDefaultPrinter().then(res => {
          e(true)
        }).catch(() => {
          a.click()
          setTimeout(() => {
            getDefaultPrinter().then(res => {
              e(true)
            }).catch(() => {
              e(false)
            })
          }, 5000)
        })
      }
      connectionState (startEvent, loadingEvent, connectionEvent, faildEvent) {
        this.contentData = {
          startEvent, loadingEvent, connectionEvent, faildEvent
        }
        const that = this
        const a = document.createElement('a')
        a.href = 'SLIENTPRINT://'
        startEvent({ isLink: false, linkLoading: true, state: 0 })
        // this.linkLoading = true
        getDefaultPrinter().then(res => {
          getPrinters().then(list => {
            connectionEvent({ isLink: true, linkLoading: false, choosePrint: res, printList: list, state: 1 })
            window.removeEventListener('focus', that.onfocus)
            window.removeEventListener('blur', that.onblur)
          })
        }).catch(() => {
          const a = document.createElement('a')
          a.href = 'SLIENTPRINT://'
          a.click()
          loadingEvent({ isLink: false, linkLoading: true, state: 0 })
          setTimeout(() => {
            getDefaultPrinter().then(res => {
              getPrinters().then(list => {
                this.printList = list
                connectionEvent({ isLink: true, linkLoading: false, choosePrint: res, printList: list, state: 1 })
                window.removeEventListener('focus', that.onfocus)
                window.removeEventListener('blur', that.onblur)
              })
            }).catch(() => {
              faildEvent({ isLink: false, linkLoading: false, state: 2 })
              window.removeEventListener('focus', that.onfocus)
              window.removeEventListener('blur', that.onblur)
            })
          }, 5000)
        })
      }
    }
    Vue.prototype.Dom2Print = Dom2Print
  }
}

到此为止,所有准备工作就绪!

开始使用

vue:

data : printClass: new this.Dom2Print()

获取默认打印机

this.printClass.getDefaultPrint((name) => {这里的name就是默认打印机名称})

获取打印机列表

this.printClass.getPrintList((list) => {这里的list就是打印机列表})

打印DOM

<div style="overflow:hidden; width:1px; height:1px">
    <div id="pdfCentent" style="width:583px;margin: 0 auto; background-size: 583px 826px; position: relative; font-size: 15px; font-family:'黑体' ">
		要被打印的dom结构~
    </div>
</div>
this.printClass.printDom(this, 'A4'或者'A5', '打印机名称', 成功后执行函数, 失败后执行的函数)
// 打印机名称可通过 this.printClass.getDefaultPrint((name) => {这里的name就是默认打印机名称})

打印url(目前仅支持pdf)

this.printClass.printUrl(url, size, 成功后执行函数, 失败后执行的函数)
// size 为A4 或者 A5 这两种的字符串

唤醒打印服务(针对不小心关闭打印服或未开启打印服务)

this.printClass.openEXE((e) => {e为true时唤醒成功, false时唤醒失败}

检测用户是否安装打印服务,若安装则启动打印服务

this.printClass.connectionState(开始启动时执行的函数, 启中执行的函数, 启动打印成功的函数, 检测到用户未安装执行的函数)

总结

  由于最近一直比较忙,这套东西写的比较急,代码不够简洁, 但目前没有什么影响流程的bug。
  
  在csdn做伸手党也很久了,也是最近刚刚开始在博客上更新自己的原创文章。
  关于无感打印这个东西,虽然业务上用到的地方不多,但我个人觉得这个思路还是挺有意思的,当然我会在有空闲时
间的时候优化上传到npm里面。 同时我会在csdn更新我这边打印功能的进度。
  
  当然有问题也欢迎大家随时留言。(尤其是新功能需求!)

严禁商用,转载请注明出处。

扫码加作者,欢迎提问。
微信扫码加作者进群,白天也许会在,欢迎交流及提问。

bd云随时可能挂掉,挂到我自己的服务器里面了:点我下载

链接都挂掉了 安装包地址请联系作者

  • 24
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
Vue前端实现静默打印的方法可以通过以下步骤实现: 1. 首先,引入一个隐藏的iframe元素,并将其设置为不可见。这可以通过在Vue组件的`template`中添加一个`<iframe>`元素,并设置属性`style="display: none;"`来实现。 2. 在需要进行静默打印的逻辑代码中,通过获取该iframe元素的引用,并设置其src属性为需要打印的内容。这可以通过在Vue组件的`methods`中添加一个方法,然后在需要打印的地方调用该方法来实现。 3. 通过在iframe元素的`load`事件中执行打印操作,实现静默打印。在Vue组件的`mounted`生命周期钩子中,监听iframe元素的`load`事件,并在事件触发时执行打印操作。 综上所述,以下是一个示例的Vue组件代码,实现了静默打印的功能: ```vue <template> <div> <iframe ref="printIframe" style="display: none;"></iframe> <button @click="handlePrint">打印</button> </div> </template> <script> export default { methods: { handlePrint() { const printContent = '<h1>要打印的内容</h1>'; // 替换成需要打印的内容 const iframe = this.$refs.printIframe; iframe.srcdoc = printContent; } }, mounted() { const iframe = this.$refs.printIframe; iframe.onload = () => { iframe.contentWindow.print(); }; } }; </script> ``` 在上面的示例中,`handlePrint`方法用于设置iframe元素的srcdoc属性为需要打印的内容。`mounted`生命周期钩子监听iframe元素的load事件,事件触发后执行iframe.contentWindow.print()操作进行静默打印。通过点击"打印"按钮,即可实现静默打印功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李二苟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值