如何实现最真实的web打印javascript
公司组织了体检,在医院发现可使用身份证快捷打印体检单,以为很方便,但仔细一看,打印效果极差。css
注:如直接调用Ctrl + P,则是打印当前的视口,能够选择打印机及打印机纸张,这显然不知足业务要求;若调用window.print(),则只能将css写在html上一块儿传到打印机,且没法预设打印机及纸张和其余设置,也不能保存模板。翻阅了一下大部分打印,都是调用window.print()去实现,都存在一下问题:html
打印样式、排版问题。
没法限定预设打印机、打印机纸张及保存为模板。
自定义纸张问题。
浏览器显示与打印结果不一致。
恰巧须要作打印功能,因而决定重构,解决上面的问题。我采用的是第二种方案并集成PAZU云打印,使用c++开发的一个exe脚本,在运行时与本机Websocket链接返回打印信息。须要详细了解的同窗请移步:PAZU官网前端
打印结果在测试后趋向于真实打印,与web显示几乎一致。vue
整体的思路是将打印机设备参数可视化,可配置,可预设到点击打印时传到打印设备上。不支持自定义就先同步到打印机,而后选择。java
比较典型的ERP详情页面,包含主表Form和子表Table明细node
GetSlideInfo () {
let CondiData = []
let SlideInfoVnode = this.$refs.SlideInfo.$children[0]
let FormItems = findComponentsDownward(SlideInfoVnode, 'FormItem')
FormItems.forEach((item, itemIndex) => {
let field = item.$children
if (field.length) {
const fieldVnode = item.$children[0]
let fieldValue = this.GetExportFieldValue(fieldVnode)
let formItem = {
key: item.prop,
label: item.label.split(':')[0],
value: fieldValue,
index: itemIndex
}
Object.assign(formItem, fieldVnode.print)
CondiData.push(formItem)
}
})
return CondiData
}
复制代码
使用findComponentsDownward获取全部的FormItem,而后获取FormItem的
VueComponment
,在组件实例里获取到打印信息。
为了支持列表批量打印详情,因而注册了一个v-print:c++
import { typeOf } from '@/libs/util'
export default {
inserted: (el, { value, arg }, vnode) => {
if (!value) return
if (typeOf(value) != 'object') value = {}
vnode.componentInstance.print = Object.assign(value, { renderType: arg || 'input' })
},
update: (el, { value, arg }, vnode) => {
if (!value) return
if (typeOf(value) != 'object') value = {}
vnode.componentInstance.print = Object.assign(value, { renderType: arg || 'input' })
}
}
复制代码
而后在页面这样书写,便可在inserted时挂载到组件实例data上。web
v-print:pick="{id:'orderBranchId',code:'orderBranchCode',name:'orderBranchName'}"
复制代码
在构造数据以前,咱们要造好动态路由并加入前端路由白名单:api
{
path: '/print',
name: 'print',
component: Main,
children: [{
path: 'print-setting/:sheetType',
name: 'print-setting',
meta: {
title: '打印设置'
},
component: () => import('@/view/main-components/print-setting.vue')
}]
}
复制代码
要保持数据持久化,因而我将数据保存到store并同时set到sessionStorage:
import { setSession } from '@/libs/session.js'
export default {
state: {
printTabs: {}
},
mutations: {
setPrintTab (state, tab) {
state.printTabs[tab.route] = tab.data
setSession(tab.route, tab.data)
}
}
}
复制代码
构造好数据以后进入打印页面:
this.setPrintTab({ route: this.$route.meta.code, data: params })
this.$router.push({ name: 'print-setting', params: { sheetType: this.$route.meta.code } })
复制代码
打印拖拽项由四个可拖拽的draggable组成,可相互拖拽,这里采用的是vuedraggable。
<Row style="height:100%">
<Form style="height:100%" justify :label-position="labelPositon" ref="formList">
<draggable id="formList" :list="formList" style="height:100%" group="people" :animation="150" :ghostClass="cls+'-left-item-chosen'">
<Col
:span="8*item.span"
:class="[cls+'-form-item',{'item-select':item.selected}]"
v-for="(item, index) in formList"
:key="index"
@click.native="handleFormItemClick(item, index)"
>
<form-item v-if="!item.blank" :label="item.label" >{{item.value}}</form-item>
<div :class="cls+'-blank'" v-else></div>
</Col>
</draggable>
</Form>
</Row>
复制代码
设置4个可拖拽group相同便可相互拖拽。
读取本机打印机:
PAZU.TPrinter.getPrinters()
复制代码
读取当前打印机纸张:
PAZU.TPrinter.getPaperForms()
复制代码
打印及打印校验:
validatePrintExe () {
return new Promise((resolve, reject) => {
PAZU.TPrinter.getPrinters(res => {
if (res === 'err') {
resolve(false)
} else {
resolve(true)
}
})
})
},
async handlePrint () {
if (await this.validatePrintExe()) {
this.doPageSetup()
PAZU.print('printContent', null, null, true)
api.updatePrintCount({ ids: Object.values(this.printData.ids).join('~&z') }, this.printData.action)
} else {
this.showPrintDownLoad = true
}
}
复制代码
同步自定义纸张到打印机:
handleSynchronizeComfirm () {
this.$refs.synchronizeForm.validate(valid => {
if (valid) {
PAZU.TPrinter.createPaper(this.baseSetting.width, this.baseSetting.height, (res) => {
if (res) {
this.$Message.warning(`规格【${res}】的纸张已存在。`)
} else {
this.showPrintor = false
this.$Message.info('同步成功。')
}
}, this.synchronize.printName, this.synchronize.pageName)
}
})
}
复制代码
一套打印下来问题重重,需求也巨大,但在写文档章时发现不知该如何把可移植的思想及技术难点单方面的开放出来。这以后的文章我也不知如何写起。
详细能够看我以前写的《修改vue源码实现对key的keep-alive》)后面我会针对源码详细讲解为什么要修改源码,为什么动态路由keep-alive失败。vue3.0正式发布以后我会第一之间测试3.0keep-alive。