vue-pdf实现预览pdf并使用C-Lodop实现打印功能

  • vue-pdf实现预览pdf并使用C-Lodop实现打印功能已关闭评论
  • 91 次浏览
  • A+
所属分类:Web前端
摘要

本人的工作项目中,需求是:  点击“打印”按钮,打开pdf预览弹出框,弹出框有:头部选择打印模板、打印方式、打印机,都是下拉选择框;中部是pdf预览块;底部是确定打印。

本人的工作项目中,需求是:

  点击“打印”按钮,打开pdf预览弹出框,弹出框有:头部选择打印模板、打印方式、打印机,都是下拉选择框;中部是pdf预览块;底部是确定打印。

 

准备工作:

  预览pdf,后端接口返回了pdf预览地址,可在线直接打开。vue-pdf插件可以满足需求。

  选择方式如果选择本地打印,下拉列表是该电脑所连接的所有打印设备,且连接打印机打印出pdf内容。我司花钱购买了C-Lodop商用产品,用这个打印控件可以满足需求。官方地址:http://www.lodop.net/

 

直接上关键代码,温馨提示:预览pdf在最后

  一、由于项目中许多地方会用到该打印预览弹框,封装一个print.vue组件文件,核心代码:

  1、打印机下拉资源获取:

    首先是:LodopFuncs.js文件,官网可以下载,根据本人工作需求情况,做了一些改动。

//= =本JS是加载Lodop插件或Web打印服务CLodop/Lodop7的综合示例,可直接使用,建议理解后融入自己程序== // 资料链接:http://www.lodop.net/  import message from 'ant-design-vue/es/message' import modal from 'ant-design-vue/es/modal'  let CLodopIsLocal, CLodopJsState  //= =判断是否需要CLodop(那些不支持插件的浏览器):== function needCLodop () {   try {     const ua = navigator.userAgent     if (ua.match(/WindowssPhone/i)) return true     if (ua.match(/iPhone|iPod|iPad/i)) return true     if (ua.match(/Android/i)) return true     if (ua.match(/EdgeD?d+/i)) return true      const verTrident = ua.match(/TridentD?d+/i)     const verIE = ua.match(/MSIED?d+/i)     let verOPR = ua.match(/OPRD?d+/i)     let verFF = ua.match(/FirefoxD?d+/i)     const x64 = ua.match(/x64/i)     if ((!verTrident) && (!verIE) && (x64)) return true     else if (verFF) {       verFF = verFF[0].match(/d+/)       if ((verFF[0] >= 41) || (x64)) return true     } else if (verOPR) {       verOPR = verOPR[0].match(/d+/)       if (verOPR[0] >= 32) return true     } else if ((!verTrident) && (!verIE)) {       let verChrome = ua.match(/ChromeD?d+/i)       if (verChrome) {         verChrome = verChrome[0].match(/d+/)         if (verChrome[0] >= 41) return true       }     }     return false   } catch (err) {     return true   } }  // 加载CLodop时用双端口(http是8000/18000,而https是8443/8444)以防其中某端口被占, // 主JS文件名“CLodopfuncs.js”是固定名称,其内容是动态的,与其链接的打印环境有关: function loadCLodop () {   if (CLodopJsState === 'loading' || CLodopJsState === 'complete') return   CLodopJsState = 'loading'   const head = document.head || document.getElementsByTagName('head')[0] || document.documentElement   const JS1 = document.createElement('script')   const JS2 = document.createElement('script')   console.log(window.location.protocol === 'https:', 'https')    // if (window.location.protocol === 'https:') {   //   JS1.src = 'https://localhost.lodop.net:8443/CLodopfuncs.js'   //   JS2.src = 'https://localhost.lodop.net:8444/CLodopfuncs.js'   // } else {   JS1.src = 'http://localhost:8000/CLodopfuncs.js'   JS2.src = 'http://localhost:18000/CLodopfuncs.js?priority=1'   // }   JS1.onload = JS2.onload = function () { CLodopJsState = 'complete' }   JS1.onerror = JS2.onerror = function (evt) { CLodopJsState = 'complete' }   head.insertBefore(JS1, head.firstChild)   head.insertBefore(JS2, head.firstChild)   CLodopIsLocal = !!((JS1.src + JS2.src).match(///localho|//127.0.0./i)) }  /**  * @description: 提示下载  * @param {String} href 下载地址  * @return {*}  */ function modalOfDownload (href) {   const content = '打印控件需要升级!点击【确定】下载并执行安装'   modal.confirm({     content,     onOk () {       const a = document.createElement('a')       a.href = 'https://test-xxxxxxxxx.cos.ap-xxx.xxx.com/kits/' + href       document.body.appendChild(a)       a.click()       a.remove()     }   }) }  /**  * @description: 获取LODOP对象主过程,判断是否安装、需否升级  * @return {Object} { state: 3 , LODOP,   message: '' } state: 1未安装、2未运行、3具备打印条件  */ function getLodop () {   let LODOP    try {     if (needCLodop()) {       try {         LODOP = window.getCLodop()       } catch (err) {}        console.log('CLodopJsState', CLodopJsState)       if (!LODOP && CLodopJsState !== 'complete') {         if (CLodopJsState === 'loading') {           message.info('网页还没下载完毕,请稍等一下再操作.')         } else {           message.info('未曾加载Lodop主JS文件,请先调用loadCLodop过程.')         }         return { state: 0 }       }        // 不存在则提示安装       if (!LODOP) {         if (CLodopIsLocal) {           return { state: 2, message: '此前已安装过,点击【运行】直接再次启动' }         } else {           return { state: 1, message: 'Web打印服务CLodop未安装启动,点击下载执行并安装' }         }       } else {         // 判断版本         const isWinIE = (/MSIE/i.test(navigator.userAgent)) || (/Trident/i.test(navigator.userAgent))         const isWinIE64 = isWinIE && (/x64/i.test(navigator.userAgent))         if (window.CLODOP.CVERSION < '4.1.5.5') {           const exeHref = isWinIE64 ? 'install_lodop64.exe' : 'install_lodop32.exe'           modalOfDownload(exeHref)           return { state: 0 }         }       }     }      if (LODOP) {       //= ==如下空白位置适合调用统一功能(如注册语句、语言选择等):=======================       LODOP.SET_LICENSES('', '7***************9', '', '')       console.log('SET_LICENSES执⾏了')        // LODOP.SET_LICENSES('', '13*******39', 'ED*******10', 'D6**********8')        //= ==============================================================================       return { state: 3, LODOP, message: '具备打印条件' }     }   } catch (err) {     console.error('getLodop出错:' + err)   } }  if (needCLodop()) { loadCLodop() } // 开始加载 export { getLodop }

  项目中引入:

import { getLodop } from '@/utils/LodopFuncs' 

  methods方法中使用:

  /**      * @description: 获取本地已连接打印机      */     getLocalPrinter () {       const lop = getLodop()       console.log('lop对象', lop)        if (!lop.state) return        if ([1, 2].includes(lop.state)) {         this.initPrinterOptions()         this.showPlugin = true         return       }        this.LODOP = lop.LODOP       const counter = this.LODOP.GET_PRINTER_COUNT() // 获取打印机个数       console.log(counter, '获取打印机个数')        var printNameList = []       for (let i = 0; i < counter; i++) {         const printerName = this.LODOP.GET_PRINTER_NAME(i)         printNameList.push({ printerName, id: printerName })       }       this.printerOptions = JSON.parse(JSON.stringify(printNameList)) // 打印机下拉列表资源     }

  2、连接打印机,打印出pdf在线地址的内容:

    (1)上面的打印机资源完成赋值以后,下拉选择你需要打印的打印机,并记住选择的id。

    (2)点击弹框的确定,开始打印,执行方法如下:

  /**      * @description: 本地打印      */     doLocalPrint () {       console.log(this.LODOP.PRINT_INIT, 'lodop是否运行')       if (!this.LODOP.PRINT_INIT) {         // 考虑中途卸载或者停用的情况,再提示打印插件下载,弹出插件下载提示框         this.initPrinterOptions()         this.showPlugin = true         return       }        // 开启懒加载       this.loading.confirm = true       this.$message.loading('准备打印中...', 0)        // 打印初始化配置       this.LODOP.PRINT_INIT(`${this.title}_${dateUtils.format('yyyyMMdd')}`)       this.LODOP.SET_PRINTER_INDEX(this.dataForm.printerId)        // 循环打印 【我们项目存在批量打印,所以需要一张张加进去再打印】       for (let i = 0; i < this.printList.length; i++) {         const pdfIm = this.printList[i]         const pageWidth = pdfIm.pageWidth ? Math.floor(pdfIm.pageWidth / 1.1756) : 2050         console.log(pageWidth, '本地打印宽度')         this.LODOP.SET_PRINT_PAGESIZE(1, pageWidth, pdfIm.pageHeight) // http://www.lodop.net/demolist/PrintSample5.html         this.LODOP.ADD_PRINT_PDF(0, 0, '100%', '100%', this.demoDownloadPDF(pdfIm.urls)) // (Top,Left,Width,Height,strURLorContent) 上边距/左边距/         // this.LODOP.ADD_PRINT_HTM(0, '5mm') // http://www.lodop.net/demolist/PrintSample46.html         this.LODOP.PRINT() // 执行打印       }        this.$message.success('单据打印中...')       // 关闭处理       this.loading.confirm = false     },    demoDownloadPDF (url) {       if (!/^https?:/i.test(url)) return       let xhr = null       if (window.XMLHttpRequest) xhr = new XMLHttpRequest()       else xhr = new window.ActiveXObject('MSXML2.XMLHTTP')       xhr.open('GET', url, false) // 同步方式       if (xhr.overrideMimeType) {         try {           xhr.responseType = 'arraybuffer'           var arrybuffer = true         } catch (err) {           xhr.overrideMimeType('text/plain; charset=x-user-defined')         }       }       xhr.send(null)       var data = xhr.response || xhr.responseBody       let dataArray = null       if (typeof Uint8Array !== 'undefined') {         if (arrybuffer) dataArray = new Uint8Array(data)         else {           dataArray = new Uint8Array(data.length)           for (var i = 0; i < dataArray.length; i++) {             dataArray[i] = data.charCodeAt(i)           }         }       } else dataArray = window.VBS_BinaryToArray(data).toArray() // 兼容IE低版本       return this.demoGetBASE64(dataArray)     },     demoGetBASE64 (dataArray) {       var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='       var strData = ''       for (var i = 0, ii = dataArray.length; i < ii; i += 3) {         if (isNaN(dataArray[i])) break         var b1 = dataArray[i] & 0xff         var b2 = dataArray[i + 1] & 0xff         var b3 = dataArray[i + 2] & 0xff         var d1 = b1 >> 2         var d2 = ((b1 & 3) << 4) | (b2 >> 4)         var d3 = i + 1 < ii ? ((b2 & 0xf) << 2) | (b3 >> 6) : 64         var d4 = i + 2 < ii ? b3 & 0x3f : 64         strData +=           digits.substring(d1, d1 + 1) +           digits.substring(d2, d2 + 1) +           digits.substring(d3, d3 + 1) +           digits.substring(d4, d4 + 1)       }       return strData     }

  3、vue-pdf预览:

    (1)页面元素核心代码:

    <!-- pdf预览 -->       <div class="preview" v-loading="loading.preview">         <template v-if="pdfList.length">           <template v-for="pdfItem in pdfList">             <pdf v-for="(pPage, pIdx) in pdfItem.numPages" :key="pIdx + pdfItem.id" :page="pPage" :src="pdfItem.src" />           </template>         </template>         <empty v-else text="暂无预览结果" />       </div>

    (2)script的data部分:

      导入:

import pdf from 'vue-pdf'

      关键变量:

printList: [], // 打印的数据列表 pdfList: [], // pdf文件列表

    (3)拿到后端返回的数据后,转化为vue-pdf插件可用数据:

// 请求数据api const { res } = await this.$caputured(this.$api[this.config.apiName], params)  if (res) {     this.printList = res.data     this.setPdfSrc(res.data)  } else {     this.pdfList = [] // 清除pdf列表     this.printList = [] // 清除pdf列表  }

   /**      * @description: 设置pdf      */     async setPdfSrc (pdfUrls) {       const list = []       for (let i = 0; i < pdfUrls.length; i++) {         const loadingTask = pdf.createLoadingTask({           url: pdfUrls[i].urls, // pdf地址           cMapUrl: 'https://cdn.jsdelivr.net/npm/[email protected]/cmaps/', // 加载字体包           cMapPacked: true         })         await loadingTask.promise.then((p) => {           list.push({             id: pdfUrls[i].id,             src: loadingTask,             numPages: p.numPages           })         })       }       this.pdfList = list     }

  4、其他情况,弹出的提示框按钮需求,有运行c-lodop和下载:

<a-button class="margin-right-8" @click="loadClodop">运行</a-button> <a-button type="primary" @click="downloadClodop">下载并安装</a-button>      /**      * @description: 运行      */     loadClodop () {       // 查看本机是否安装(控件或web打印服务)       const lop = getLodop()       if (lop.state === 1) this.$message.warn(lop.message, 3)       else if (lop.state === 2) {         // 手动触发运行         const a = document.createElement('a')         a.href = 'CLodop.protocol:setup'         a.target = '_self'         document.body.appendChild(a)         a.click()         a.remove()         this.showPlugin = false       }     },       /**      * @description: 下载      */     downloadClodop () {       const a = document.createElement('a')       a.href = '下载地址'       document.body.appendChild(a)       a.click()       this.showPlugin = false     }

  完毕。欢迎指出。