vue3+ts实现打印以及封装打印hooks
vue
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
项目地址:https://gitcode.com/gh_mirrors/vu/vue
免费下载资源
·
最近在写vue3项目的时候碰到一些重复的需求,也就是后台管理系统的打印模块,打印与后端沟通,返回的是html格式,前端通过v-html解析即可
1.插件选择:这里打印插件选择了print-js用来做打印,因为该插件可以解析html,img等格式同时支持局部打印(针对DOM的id属性等),所以选择这个,打印效果如下
2.打印公共组件封装
2.1先看后端返回数据格式:
2.2可以看到是一个html数组,所以打印组件使用v-html解析时应该是个数组 ,所以组件封装如下
// 打印公共组件
<template>
<div id="print_area" class="print-area">
<div v-for="(item, index) in htmlArrays" :key="index" v-html="item" style="page-break-after: always"></div>
</div>
</template>
<script setup lang="ts">
import { computed, nextTick } from 'vue'
import print from 'print-js'
const _props = defineProps(['htmlArrays'])
const _emits = defineEmits(['printDialogChange'])
const htmlArrays = computed(() => _props.htmlArrays)
// page-break-after: always 此样式用于打印分页
// 打开此样式可取消页眉页脚
// const style = '@page {margin:0 10mm};'
const toPrint = () => {
nextTick(() => {
print({
printable: 'print_area',
type: 'html',
// style,
scanStyles: false,
// 浏览器打印对话框关闭钩子
onPrintDialogClose() {
_emits('printDialogChange')
},
// PDF加载后钩子
onLoadingEnd() {
_emits('printDialogChange')
},
})
})
}
defineExpose({ toPrint })
</script>
<style scoped lang="less">
.print-area {
display: none;
position: fixed;
left: -1000px;
top: -1000px;
}
</style>
2.3 父组件在调用,只需要请求到数据使用props传给子组件,调用子组件打印方法即可唤起浏览器预览打印
// 使用组件
<receivePrint :htmlArrays="htmlArrays" ref="printDom" />
// 引入组件
import receivePrint from '@/components/content-print/index.vue'
const printDom = ref() // 打印dom
const htmlArrays = ref<string[]>([]) // 打印数组
/**
* @method 给指定字符串的指定位置插入指定字符串
* @param source 要插入的字符串
* @param start 开始位置
* @param newStr 插入的字符串
* @returns 返回插入后的源字符串
*/
const insertStr = (source: string, start: number, newStr: string): string => {
return source.slice(0, start) + newStr + source.slice(start)
}
// 从后端请求到的数据
const handlePrint = async (type: 'single' | 'all', record?: any) => {
const params = { wahousingPlanDetailId: goodsState.value['id'], wahousingPlanId: goodsState.value['warehousingPlanId'], items: [] as any[] }
let printItems: Record<string, string | number>
if (type === 'single') {
printItems = { shJs: record.total, shSl: `${record.total}件`, trackCode: record.trackingNumber, pieceWeight: record.pieceWeight }
params['items'].push(printItems)
}
if (type === 'all') {
contentTableParam.dataSource.forEach((el: { total: number; trackingNumber: string; pieceWeight: number }) => {
printItems = { shJs: el.total, shSl: `${el.total}件`, trackCode: el.trackingNumber, pieceWeight: el.pieceWeight }
params['items'].push(printItems)
})
}
// 此处请求后端数据,上面不用看
const { Success, ResultCode, Tag } = await globalProperties.$api.receiving_api.receivingPrintByteArray(params)
if (Success && ResultCode === 200) {
Tag.forEach((v: string) => {
// 给每一个html插入margin:0的样式
v = insertStr(v, -14, '<style>body{margin:0}</style>')
})
htmlArrays.value = Tag
printDom.value.toPrint()
}
}
3.由于后续业务庞大,打印的模块很多,索性将打印封装成了业务hooks
3.1在src/hooks目录下新建usePrint.ts文件
3.2 封装时要考虑hooks的健壮性以及拓展性,所以子组件的ref,htmlArrays,都可定义到hooks里最后return出去
3.3代码如下:
3.3.1:可以看到handlePrint函数需要我们传入2个参数,一个是请求的钩子,一个是请求参数,此函数会自动发起请求并唤醒子组件的打印
import { ref, getCurrentInstance } from 'vue'
/**
* @method 打印hooks
* @returns {*}
*/
export default function usePrint(): any {
const print = ref(null) // 下拉框选中值,用来指定templateId
const printDom = ref() // 打印Ref绑定dom
const printOptions = ref([]) // 打印下拉选项
const htmlArrays = ref<string[]>([]) // 后端返回的html数组
const {
appContext: {
config: { globalProperties },
},
}: any = getCurrentInstance()
/**
* @method 打印模版
* @param type 打印模版选项
* @returns Promise<void>
*/
async function initPrintOptions(type: string) {
const { Success, Tag } = await globalProperties.$api.goDownPlanList_api.printTemplateGetTemplateList({ type })
if (Success) {
printOptions.value = Tag
}
}
/**
* @method 下拉选择打印
* @param cb 请求回调函数
* @param params 请求参数
* @returns Promise<void>
*/
async function handlePrint(cb: (arg: Record<string, any>) => Promise<{ Success: boolean; Tag: string[] }> | { Success: boolean; Tag: string[] }, params: Record<string, any>) {
if (!print.value) {
globalProperties.$message.error('请先选择打印模板')
return
}
const { Success, Tag } = await cb(params)
if (Success) {
htmlArrays.value = Tag
printDom.value.toPrint()
}
}
/**
* @method 托盘单条/多条打印
* @param cb 打印请求回调
* @param params 请求参数
* @returns Promise<void>
*/
async function labelPrint(cb: (arg: Record<string, any>) => Promise<{ Success: boolean; Tag: string[] }> | { Success: boolean; Tag: string[] }, params: Record<string, any>) {
const { Success, Tag } = await cb(params)
if (Success) {
htmlArrays.value = Tag
printDom.value.toPrint()
}
}
/**
* @method 打印dialog弹出或关闭
* @returns void
*/
function printDialogChange() {
print.value = null
}
return {
print,
printDom,
htmlArrays,
printOptions,
handlePrint,
initPrintOptions,
printDialogChange,
labelPrint,
}
}
3.3.2 父组件代码可更新为
<godownPlanPrint :htmlArrays="htmlArrays" ref="printDom" />
import usePrint from '@/hooks/usePrint'
// 把打印所需操作从hooks解构出来,因为此模块需要其他方法,就一起解构出来了
const { htmlArrays, handlePrint, initPrintOptions, printDialogChange, printOptions, print, printDom } = usePrint()
// 普通模块只需要关注handlePrint函数即可
//调用接口时只需要执行以下代码
const params = {
linkIds: contentTableParam.selectedRowKeys,
templateId: print.value,
}
//调用hooks打印,传入请求的钩子与请求参数即可实现打印
handlePrint(globalProperties.$api.goDownPlanList_api.warehousingPlanPrint, params)
GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5
* chore: fix link broken
Signed-off-by: snoppy <michaleli@foxmail.com>
* Update packages/template-compiler/README.md [skip ci]
---------
Signed-off-by: snoppy <michaleli@foxmail.com>
Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891
Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
更多推荐
已为社区贡献3条内容
所有评论(0)