前端局部导出PDF(非图片,可编辑)功能,iframe无感预览,部署在qiankun主应用里也适用√
1、使用windows.print()
2、待导出部分放在隐藏的iframe里面,达到无感预览的交互体验
3、需要考虑部署在qiankun主应用中样式丢失的问题
有【导出pdf】按钮的页面
<template>
<div>
<iframe
id="frame"
:src="getPath"
ref="iframe"
style="display: none"
></iframe>
</div>
</template>
<script>
export default {
name: 'ApiDialog',
data() {
return {
multipleSelection: [],
}
},
mounted() {
window.addEventListener('message', (e) => {
let data = e.data
if (data.key === '咩哈哈') {
//刷新iframe
this.$refs.iframe.contentWindow.location.reload(true)
}
})
},
computed: {
getPath() {
let _path = window.location.href
_path = _path.replace('open-api', 'preview-pdf')
return _path
},
},
methods: {
previewPdf() {
if (this.multipleSelection.length === 0) {
this.$message.warning('请选择要预览的数据!')
} else {
this.$refs.iframe.contentWindow.postMessage(
{
key: '啦啦啦',
params: {
// 传过去的值
previewList: JSON.stringify(this.multipleSelection),
},
},
'*'
)
}
},
},
}
</script>
待导出为pdf的页面
<template>
<div>
<!--startprint-->
<div
v-for="(item, index) in previewList"
:key="index"
style="padding-left: 20px; line-height: 1.2"
>
<div>
<h3>
{{ index + 1 }}. {{ item.apiName }}
</h3>
</div>
<p>所属服务:{{ item.serviceName }}</p>
<p>接口描述:{{ item.apiDesc }}</p>
<p>接口路径:{{ item.apiPath }}</p>
<p>
接口类型:
<span
class="ct-tag"
:style="{ background: getRequestTypeColor(item.apiMethod) }"
>
{{ item.apiMethod }}
</span>
</p>
<p>接口入参:-</p>
<p>接口反参:-</p>
<el-divider></el-divider>
</div>
<!--endprint-->
</div>
</template>
<script>
import { getRequestTypeColor } from '@/mapping'
export default {
name: 'PreviewPdf',
props: {},
data() {
return {
getRequestTypeColor,
previewList: [],
}
},
created() {},
mounted() {
window.addEventListener(
'message',
(e) => {
let data = e.data
if (data.key === '啦啦啦') {
//iframe不接收[object array],所以需要转成字符串传递
this.previewList = JSON.parse(data.params.previewList)
this.$nextTick(() => {
this.doPrint()
window.parent.postMessage(
{
key: '咩哈哈',
},
'*'
)
})
}
},
false
)
},
methods: {
doPrint() {
//为了匹配qiankun主应用(其实是主应用强制加的layout,没有考虑到子应用某些场景不需要主应用layout例如子应用的有些页面需要全屏or打印的需求),直接替换的话打包出来的自定义css也会被替换掉,
//应该有更好的解决方法,因为el-tag什么的样式也不生效,偷懒自己重写了个tag样式
//另外这个正则表达式会使ide报红= =。
let reg = /<div id="__qiankun_microapp(([\s\S])*?)<\/style><\/div>/g
let html = window.document.body.innerHTML
let arr = html.match(reg)
if (arr) {
window.document.body.innerHTML = arr[0]
window.print()
} else {
//因为在子应用的页面路由里给它配了一份左侧菜单(layout),如果不配的话只用下面两行就可以了:
//window.document.body.innerHTML=html
//window.print()
let bdhtml = html
const sprnstr = '<!--startprint-->'
const eprnstr = '<!--endprint-->'
let prnhtml = bdhtml.substr(bdhtml.indexOf(sprnstr) + 17)
prnhtml = prnhtml.substring(0, prnhtml.indexOf(eprnstr))
window.document.body.innerHTML = prnhtml
window.print()
}
},
},
}
</script>
<style lang="scss" media="print" scoped>
.ct-tag {
color: white;
border-radius: 4px;
display: inline-block;
height: 24px;
padding: 0 8px;
line-height: 22px;
font-size: 12px;
//使打印时的背景色生效
-webkit-print-color-adjust: exact;
}
</style>