vxe-pc-ui
Version:
A vue based PC component library
245 lines (222 loc) • 8.95 kB
text/typescript
import { defineComponent, ref, h, reactive, PropType, provide, createCommentVNode } from 'vue'
import XEUtils from 'xe-utils'
import { getConfig, createEvent } from '../../ui'
import { printHtml } from './util'
import { getSlotVNs } from '../..//ui/src/vn'
import type { VxePrintPropTypes, PrintReactData, PrintPrivateRef, VxePrintEmits, PrintPrivateMethods, ValueOf, VxePrintPrivateComputed, VxePrintConstructor, VxePrintPrivateMethods, PrintMethods } from '../../../types'
export default defineComponent({
name: 'VxePrint',
props: {
align: {
type: String as PropType<VxePrintPropTypes.Align>,
default: () => getConfig().print.align
},
title: String as PropType<VxePrintPropTypes.Title>,
headerAlign: {
type: String as PropType<VxePrintPropTypes.HeaderAlign>,
default: () => getConfig().print.headerAlign
},
footerAlign: {
type: String as PropType<VxePrintPropTypes.FooterAlign>,
default: () => getConfig().print.footerAlign
},
showPageNumber: {
type: Boolean as PropType<VxePrintPropTypes.ShowPageNumber>,
default: () => getConfig().print.showPageNumber
},
customLayout: Boolean as PropType<VxePrintPropTypes.CustomLayout>,
pageBreaks: Array as PropType<VxePrintPropTypes.PageBreaks>,
content: String as PropType<VxePrintPropTypes.Content>,
html: String as PropType<VxePrintPropTypes.Html>,
headerHtml: String as PropType<VxePrintPropTypes.HeaderHtml>,
footerHtml: String as PropType<VxePrintPropTypes.FooterHtml>,
leftHtml: String as PropType<VxePrintPropTypes.LeftHtml>,
rightHtml: String as PropType<VxePrintPropTypes.RightHtml>,
showAllPageTitle: {
type: Boolean as PropType<VxePrintPropTypes.ShowAllPageTitle>,
default: () => getConfig().print.showAllPageTitle
},
customStyle: {
type: String as PropType<VxePrintPropTypes.CustomStyle>,
default: () => getConfig().print.customStyle
},
beforeMethod: Function as PropType<VxePrintPropTypes.BeforeMethod>
},
emits: [] as VxePrintEmits,
setup (props, context) {
const { slots, emit } = context
const xID = XEUtils.uniqueId()
const refElem = ref<HTMLDivElement>()
const reactData = reactive<PrintReactData>({
staticPageBreaks: []
})
const refMaps: PrintPrivateRef = {
refElem
}
const computeMaps: VxePrintPrivateComputed = {
}
const $xePrint = {
xID,
props,
context,
reactData,
getRefMaps: () => refMaps,
getComputeMaps: () => computeMaps
} as unknown as VxePrintConstructor & VxePrintPrivateMethods
const dispatchEvent = (type: ValueOf<VxePrintEmits>, params: Record<string, any>, evnt: Event | null) => {
emit(type, createEvent(evnt, { $print: $xePrint }, params))
}
const printMethods: PrintMethods = {
dispatchEvent,
print () {
const elem = refElem.value
return printHtml(Object.assign({}, props, {
_pageBreaks: !!reactData.staticPageBreaks.length,
html: (elem ? elem.outerHTML : '') || props.html || props.content || ''
}))
}
}
const printPrivateMethods: PrintPrivateMethods = {
}
Object.assign($xePrint, printMethods, printPrivateMethods)
const renderPageConfigLayouts = () => {
const { title, showPageNumber, showAllPageTitle, align, headerAlign, footerAlign } = props
const pageBreaks = props.pageBreaks || []
const pageCount = pageBreaks.length
return pageBreaks.map((item, index) => {
const bodyHtml = item.bodyHtml
const headerHtml = item.headerHtml || props.headerHtml
const footerHtml = item.footerHtml || props.footerHtml
const leftHtml = item.leftHtml || props.leftHtml
const rightHtml = item.rightHtml || props.rightHtml
const currentPage = index + 1
const params = {
currentPage,
pageCount
}
return h('div', {
class: ['vxe-print-page-break', align ? `align--${align}` : '']
}, [
h('div', {
class: ['vxe-print-page-break--header', headerAlign ? `align--${headerAlign}` : '']
}, headerHtml
? `${XEUtils.isFunction(headerHtml) ? headerHtml(params) : (headerHtml || '')}`
: [
title && (showAllPageTitle || !index)
? h('div', {
class: 'vxe-print-page-break--header-title'
}, `${title || ''}`)
: createCommentVNode()
]),
h('div', {
class: 'vxe-print-page-break--body'
}, [
h('div', {
class: 'vxe-print-page-break--left'
}, `${XEUtils.isFunction(leftHtml) ? leftHtml(params) : (leftHtml || '')}`),
h('div', {
class: 'vxe-print-page-break--content'
}, `${XEUtils.isFunction(bodyHtml) ? bodyHtml(params) : (bodyHtml || '')}`),
h('div', {
class: 'vxe-print-page-break--right'
}, `${XEUtils.isFunction(rightHtml) ? rightHtml(params) : (rightHtml || '')}`)
]),
h('div', {
class: ['vxe-print-page-break--footer', footerAlign ? `align--${footerAlign}` : '']
}, footerHtml
? `${XEUtils.isFunction(footerHtml) ? footerHtml(params) : (footerHtml || '')}`
: [
showPageNumber
? h('div', {
class: 'vxe-print-page-break--footer-page-number'
}, `${currentPage}/${pageCount}`)
: createCommentVNode()
])
])
})
}
const renderPageStaticLayouts = () => {
const { title, showPageNumber, showAllPageTitle, align, headerAlign, footerAlign } = props
const { staticPageBreaks } = reactData
const pageCount = staticPageBreaks.length
return staticPageBreaks.map((item, index) => {
const itemSlots = item.slots || {}
const currentPage = index + 1
const defaultSlot = itemSlots.default
const headerSlot = itemSlots.header || slots.header
const footerSlot = itemSlots.footer || slots.footer
const leftSlot = itemSlots.left || slots.left
const rightSlot = itemSlots.right || slots.right
const params = {
currentPage,
pageCount
}
return h('div', {
class: ['vxe-print-page-break', align ? `align--${align}` : '']
}, [
h('div', {
class: ['vxe-print-page-break--header', headerAlign ? `align--${headerAlign}` : '']
}, headerSlot
? getSlotVNs(headerSlot(params))
: [
title && (showAllPageTitle || !index)
? h('div', {
class: 'vxe-print-page-break--header-title'
}, `${title || ''}`)
: createCommentVNode()
]),
h('div', {
class: 'vxe-print-page-break--body'
}, [
h('div', {
class: 'vxe-print-page-break--left'
}, leftSlot ? getSlotVNs(leftSlot(params)) : []),
h('div', {
class: 'vxe-print-page-break--content'
}, defaultSlot ? getSlotVNs(defaultSlot(params)) : []),
h('div', {
class: 'vxe-print-page-break--right'
}, rightSlot ? getSlotVNs(rightSlot(params)) : [])
]),
h('div', {
class: ['vxe-print-page-break--footer', footerAlign ? `align--${footerAlign}` : '']
}, footerSlot
? getSlotVNs(footerSlot(params))
: [
showPageNumber
? h('div', {
class: 'vxe-print-page-break--footer-page-number'
}, `${currentPage}/${pageCount}`)
: createCommentVNode()
])
])
})
}
const renderVN = () => {
const { customLayout } = props
const { staticPageBreaks } = reactData
const defaultSlot = slots.default
return h('div', {
ref: refElem,
class: ['vxe-print']
}, customLayout
? (defaultSlot ? getSlotVNs(defaultSlot({})) : [])
: ([
h('div', {
key: 'slot',
class: 'vxe-print-slots'
}, defaultSlot ? getSlotVNs(defaultSlot({})) : [])
].concat(
staticPageBreaks.length
? renderPageStaticLayouts()
: renderPageConfigLayouts()
)))
}
$xePrint.renderVN = renderVN
provide('$xePrint', $xePrint)
return $xePrint
},
render () {
return this.renderVN()
}
})