如何實現最真實的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。