怎样在vue项目中监测数据变化来实现自动打印

一、初代版本

初代版本中,并没有要求自动打印,要实现的是手动打印,这个功能没啥可说的,直接用
vue-print-nb这个插件就OK,实现方式也很简单,我这里简单说一下,网上很多类似教程

1、安装

npm install vue-print-nb --save

2、引入

全局如下在main.js中引入,非全局不用说了把,引入直接用就行
import Print from ‘vue-print-nb’
Vue.use(Print);

3、查找id方式打印
<div id="printMe" >
    <p>打印内容</p>
</div>
<button v-print="'#printMer'">打印</button>
其实主要在于v-print
4、对象方式打印
<button v-print="printObj">Print local range</button>
 
<div id="printMe" style="background:red;">
  <p>葫芦娃,葫芦娃</p>
  <p>一根藤上七朵花 </p>
</div>
这里是html
export default {
    data() {
        return {
            printObj: {
              id: "printMe",
              popTitle: 'good print',
              extraCss: 'https://www.google.com,https://www.google.com',
              extraHead: '<meta http-equiv="Content-Language"content="zh-cn"/>'
            }
        };
    }
}
这里是方法
id:*必填需部分打印输入的ID
standard:文档类型,默认是HTML5,可选html5,loose,strict
extraHead:附加到head标签的附加标签,以逗号分隔
extraCss:附加链接连接,以逗号分隔
popTitle:标题显示标题
endCallback():打印后的回调事件

这个就不过多介绍了,用这个插件写打印存在一个问题,那就是没法关闭预览,所以在第二版本时我进行了改变

二、更改版本

1、打印插件

CLodop云打印

2、打印方法编写
2-1、官网下载lodopFuncs.js(这个名字后面可以改,主要是里面的内容)
2-2、下载完成之后稍微改造一下(其实就是导出方法,其余不变)
var CreatedOKLodop7766 = null

//= ===判断是否需要安装CLodop云打印服务器:====
export function needCLodop() { //就改这里就好
  try {
    var ua = navigator.userAgent
    if (ua.match(/Windows\sPhone/i) != null) return true
    if (ua.match(/iPhone|iPod/i) != null) return true
    if (ua.match(/Android/i) != null) return true
    if (ua.match(/Edge\D?\d+/i) != null) return true

    var verTrident = ua.match(/Trident\D?\d+/i)
    var verIE = ua.match(/MSIE\D?\d+/i)
    var verOPR = ua.match(/OPR\D?\d+/i)
    var verFF = ua.match(/Firefox\D?\d+/i)
    var x64 = ua.match(/x64/i)
    if (verTrident == null && verIE == null && x64 !== null) {
      return true
    }
    if (verFF !== null) {
      verFF = verFF[0].match(/\d+/)
      if (verFF[0] >= 42 || x64 !== null) return true
    } else if (verOPR !== null) {
      verOPR = verOPR[0].match(/\d+/)
      if (verOPR[0] >= 32) return true
    } else if (verTrident == null && verIE == null) {
      var verChrome = ua.match(/Chrome\D?\d+/i)
      if (verChrome !== null) {
        verChrome = verChrome[0].match(/\d+/)
        if (verChrome[0] >= 42) return true
      }
    }
    return false
  } catch (err) {
    return true
  }
}

//= ===页面引用CLodop云打印必须的JS文件:====
if (needCLodop()) {
  var head =
    document.head ||
    document.getElementsByTagName('head')[0] ||
    document.documentElement
  var oscript = document.createElement('script')
  oscript.src = 'http://localhost:8000/CLodopfuncs.js?priority=1'
  head.insertBefore(oscript, head.firstChild)

  // 引用双端口(8000和18000)避免其中某个被占用:
  oscript = document.createElement('script')
  oscript.src = 'http://localhost:18000/CLodopfuncs.js?priority=0'
  head.insertBefore(oscript, head.firstChild)
}

//= ===获取LODOP对象的主过程:====
export function getLodop(oOBJECT, oEMBED) {
  var strHtmInstall =
    "<br><font color='#FF00FF'>打印控件未安装!点击这里<a href='http://www.lodop.net/download.html'>执行安装</a>,安装后请刷新页面或重新进入。</font>"
  var strHtmUpdate =
    "<br><font color='#FF00FF'>打印控件需要升级!点击这里<a href='http://www.lodop.net/download.html'>执行升级</a>,升级后请重新进入。</font>"
  var strHtm64_Install =
    "<br><font color='#FF00FF'>打印控件未安装!点击这里<a href='http://www.lodop.net/download.html' >执行安装</a>,安装后请刷新页面或重新进入。</font>"
  var strHtm64_Update =
    "<br><font color='#FF00FF'>打印控件需要升级!点击这里<a href='http://www.lodop.net/download.html'>执行升级</a>,升级后请重新进入。</font>"
  var strHtmFireFox =
    "<br><br><font color='#FF00FF'>(注意:如曾安装过Lodop旧版附件npActiveXPLugin,请在【工具】->【附加组件】->【扩展】中先卸它)</font>"
  var strHtmChrome =
    "<br><br><font color='#FF00FF'>(如果此前正常,仅因浏览器升级或重安装而出问题,需重新执行以上安装)</font>"
  var strCLodopUpdate =
    "<br><font color='#FF00FF'>CLodop云打印服务需升级!点击这里<a href='http://www.c-lodop.com/download/CLodop_Setup_for_Win32NT_https_3.008Extend.zip' target='_self'>执行升级</a>,升级后请刷新页面。</font>"
  var LODOP
  try {
    var isIE =
      navigator.userAgent.indexOf('MSIE') >= 0 ||
      navigator.userAgent.indexOf('Trident') >= 0
    if (needCLodop()) {
      try {
        LODOP = getCLodop()
      } catch (err) {}
      if (!LODOP && document.readyState !== 'complete') {
        alert('C-Lodop没准备好,请稍后再试!')
        return
      }
      if (!LODOP) {
        // if (isIE) document.write(strCLodopInstall); else
        // document.documentElement.innerHTML=strCLodopInstall+document.documentElement.innerHTML;
        // return;
        if (isIE) document.write(strHtmInstall)
        else {
          document.documentElement.innerHTML =
            strHtmInstall + document.documentElement.innerHTML
        }
        return LODOP
      } else {
        if (CLODOP.CVERSION < '3.0.0.2') {
          if (isIE) document.write(strCLodopUpdate)
          else {
            document.documentElement.innerHTML =
              strCLodopUpdate + document.documentElement.innerHTML
          }
        }
        if (oEMBED && oEMBED.parentNode) oEMBED.parentNode.removeChild(oEMBED)
        if (oOBJECT && oOBJECT.parentNode)
          oOBJECT.parentNode.removeChild(oOBJECT)
      }
    } else {
      var is64IE = isIE && navigator.userAgent.indexOf('x64') >= 0
      //= ====如果页面有Lodop就直接使用,没有则新建:==========
      if (oOBJECT != undefined || oEMBED != undefined) {
        if (isIE) LODOP = oOBJECT
        else LODOP = oEMBED
      } else if (CreatedOKLodop7766 == null) {
        LODOP = document.createElement('object')
        LODOP.setAttribute('width', 0)
        LODOP.setAttribute('height', 0)
        LODOP.setAttribute(
          'style',
          'position:absolute;left:0px;top:-100px;width:0px;height:0px;'
        )
        if (isIE)
          LODOP.setAttribute(
            'classid',
            'clsid:2105C259-1E0C-4534-8141-A753534CB4CA'
          )
        else LODOP.setAttribute('type', 'application/x-print-lodop')
        document.documentElement.appendChild(LODOP)
        CreatedOKLodop7766 = LODOP
      } else LODOP = CreatedOKLodop7766
      //= ====Lodop插件未安装时提示下载地址:==========
      if (LODOP == null || typeof LODOP.VERSION == 'undefined') {
        if (navigator.userAgent.indexOf('Chrome') >= 0) {
          document.documentElement.innerHTML =
            strHtmChrome + document.documentElement.innerHTML
        }
        if (navigator.userAgent.indexOf('Firefox') >= 0) {
          document.documentElement.innerHTML =
            strHtmFireFox + document.documentElement.innerHTML
        }
        if (is64IE) document.write(strHtm64_Install)
        else if (isIE) document.write(strHtmInstall)
        else {
          document.documentElement.innerHTML =
            strHtmInstall + document.documentElement.innerHTML
        }
        return LODOP
      }
    }
    if (LODOP.VERSION < '6.0') {
      if (!needCLodop()) {
        if (is64IE) document.write(strHtm64_Update)
        else if (isIE) document.write(strHtmUpdate)
        else {
          document.documentElement.innerHTML =
            strHtmUpdate + document.documentElement.innerHTML
        }
      }
      return LODOP
    }
    //= ==如下空白位置适合调用统一功能(如注册语句、语言选择等):===
    // LODOP.SET_LICENSES("北京XXXXX公司","8xxxxxxxxxxxxx5","","");
    //= ==========================================================
    return LODOP
  } catch (err) {
    alert('getLodop出错:' + err)
  }
}

2-3、引入后写打印方法
import { getLodop } from '@/assets/js/lodop.js'   //这是引入,文件名字自己改的


//打印新增信息
    printMeAuto() {   //这个是打印代码
      var self = this
      let LODOP = getLodop() //主要代码
      LODOP.PRINT_INIT()
      LODOP.SET_PRINT_PAGESIZE(3, 580, 200)
      LODOP.ADD_PRINT_HTM(
        0,
        0,
        '100%',
        '100%',
        document.getElementById('printMeauto').innerHTML  //获取要打印部分html
      )
      //以上为声明打印参数,具体请参照官网示例
      //以下是成功加入打印队列之后的回调,如果不用刻意不看,直接执行LODOP.PRINT()
      LODOP.SET_PRINT_MODE('CATCH_PRINT_STATUS', true)

      if (LODOP.CVERSION) {
        //判断c_lodop是否存在,安装了c-lodop就会存在
        LODOP.On_Return = function(TaskID, Value) {
          // console.log('TaskID:' + TaskID)
          console.log('Value:' + Value) //job代码
          self.jobCode = Value
          if (!!Value) {
            //如果成功,改变打印次数
            ChangePrintCount(self.newDataAuto).then((res) => {
              if (res.status !== 1) {
                self.$notify.error({
                  title: '错误',
                  message: res.message,
                })
              }
            })
            return
          }
        }
        LODOP.PRINT() //这是执行打印(无预览)
        // LODOP.PREVIEW()   这是有预览打印
        self.dialogVisible = false
        return
      } else {
        console.log('c-lodop出错了')
      }
    },

附:官网示例地址:官网示例地址

3、实现与后台实时连接

这里我们可能首先想到的是与后台建立长连接,或者进行轮询,其实这也都是这么做的,方法也有很多种,在本次项目中,与后端商量后使用了signalr来进行前后的通讯

3-1、插件安装

npm i @aspnet/signalr
本来是直接使用signalr官方的插件的,但是因为jqueryvue cli里面引入全局后signalr总是找不到jquery,即使引入在他前面也不行,改了源码之后又找不到其中一个方法,最后逼不得已换插件。

3-2、编写监听和推送方法
import { HubConnectionBuilder, LogLevel } from '@aspnet/signalr' //引入signalr
import store from '@/store/index' //引入vuex,便于数据公用
export default {
  install(Vue) {
    // 使用新的Vue实例作为Vue组件接收/发送信号器事件的接口
    // 这样,每个组件都可以使用此工具监听事件或发送新事件。$questionHub
    const questionHub = new Vue()
    Vue.prototype.$questionHub = questionHub

    // 提供连接/断开信号器集线器的方法
    let connection = null
    let startedPromise = null
    let manuallyClosed = false

    Vue.prototype.startSignalR = (jwtToken) => {
      connection = new HubConnectionBuilder()
        .withUrl( //更换地点一,地址拼接,这个请找后台要方法,或者你说后台改
          `${store.state.urlAuto}/apphub`,
          jwtToken ? { accessTokenFactory: () => jwtToken } : null
        )
        .configureLogging(LogLevel.Information)
        .build()
		//更换地点二,这是后台调用前台JS方法的注册,QuestionAddedPrint为调用方法,
		//自行更换,recoredId是返回值
      // orward hub事件,这样我们就可以在Vue组件中监听它们
      connection.on('QuestionAddedPrint', (recoredId) => {
        questionHub.$emit('question-added-print', recoredId)
      })

      // 你需要打电话连接.启动()以建立连接,但客户端不会为您处理重新连接!
      //医生建议在关闭时监听并在那里处理
      // This is the simplest of the strategies
      function start() {
        startedPromise = connection.start().catch((err) => {
          console.error('Failed to connect with hub', err)
          return new Promise((resolve, reject) =>
            setTimeout(
              () =>
                start()
                  .then(resolve)
                  .catch(reject),
              5000
            )
          )
        })
        return startedPromise
      }
      connection.onclose(() => {
        if (!manuallyClosed) start()
      })

      // Start everything
      manuallyClosed = false
      start()
    }
    //绑定启动命令
    Vue.prototype.stopSignalR = () => {
      if (!startedPromise) return

      manuallyClosed = true
      return startedPromise
        .then(() => connection.stop())
        .then(() => {
          startedPromise = null
        })
    }

    // Provide methods for components to send messages back to server
    // Make sure no invocation happens until the connection is established
    //这里是前台调用后台方法SetCurrentClientHub,这个可自行书写
    questionHub.setCurrentClientHub = () => {
      if (!startedPromise) return
      return startedPromise
        .then(() => connection.invoke('SetCurrentClientHub'))
        .catch(console.error)
    }
  },
}

我的做法是把所有方法绑在了vue的原型上,看着不舒服的请自行更改

3-3、在项目(main.js)中引入
import QuestionHub from './question-hub'   //question-hub是文件名,自己改就好
Vue.use(QuestionHub)

3-4、在需要的页面(可全局监听,看自己)使用
 created() {
    this.startSignalR() //启动SignalR开启链接,我绑在了原型上,所以直接this.就行,如果是其他绑定,请更换
    this.$questionHub.setCurrentClientHub() //这个方法没啥大用,就是调用后台的一个方法,告诉他我连上了,可以不要
    this.$questionHub.$on('question-added-print', this.print) //监听后台方法,后台一旦调用,前台就调用this.print方法
  },
print(recoredId) { //其中的recoredId是写在上面文件中的后台的返回值
      this.viewDetailAuto('', recoredId) //这个是调用接口方法,根据ID来查询要打印页面的数据,可以直接跳过
    },
//在这个方法里面就可以直接调用之前写到的打印的方法了,到这里就已经实现了,后台数据一改变就自动打印的操作

本次的分享到这里就结束了,代码上来说,大多数都是可以直接复制粘贴直接用,需要更改的地方我也都有标注,看起来其实还是略显麻烦,如果谁有更好的方法,麻烦请留言告知,感激不尽。

Logo

前往低代码交流专区

更多推荐