版权声明:本文为博主原创文章,如有错误欢迎指正,如需转载请注明出处,谢谢配合。 https://blog.csdn.net/xiaxiangyun/article/details/81117517
背景
提分加项目中遇到了一个需要前端对PDF页面进行分页的需求。该需求是要为每一位学生生成一份PDF的学习报告,起初是采用了前端提供几个页面模板,由java端调用iText去生成PDF,PDF的分页工作也由工具去完成。
但是由于页面中包含大量的数学公式、图片等一些对样式要求较高的元素,iText对很多CSS3属性的支持较差,生成的PDF经常会出现切页的情况。最后决定由前端生成分好页的页面,并提供一个方法导出当前页面的Dom节点,服务端通过访问该页面并调用此方法得到分页后的页面元素,最后调用Node的一个工具生成PDF。
而对于前端PDF分页的思路,大致分以下四步:
- 首先获取后台数据渲染页面
- 页面渲染好之后获取每个元素的高度,通过一定的算法判断各个元素应该在哪一页
- 对于跨页的元素,采用前页隐藏后页定位的模式,使之在视觉上刚好能接起来
- 完成分页
而在这个过程中因为每一页的元素是有分页后的数据所决定的,所以使用到了render函数。
代码
拿出一个模块的代码来,类似的思路就是这样,通过数据判断当前页应当渲染的元素,然后通过render函数中的createElement方法创建页面元素。
<script>
import { mapActions, mapGetters, mapState } from "vuex";
import Top from "./components/Top.vue";
import Charts from "./components/Charts.vue";
import Table from "./components/Table.vue";
export default {
name: "global-analysis",
props: {
page: { type: [Object], required: true },
},
components: { Top, Charts, Table },
computed: {
positionStyle () {
return {
position: 'absolute',
width: '100%',
top: -this.page.top + 'px',
padding: '0px 28px',
}
},
hiddenStyle () {
return {
position: 'relative',
width: '100%',
height: (1170 - this.page.hidden) + 'px',
overflow: 'hidden'
}
}
},
render (createElement) {
const children = []
//根据数据加载指定模块
this.page.blocks.forEach((block, index) => {
let component = ''
if (block.name === 'global-analysis-top') {
component = 'Top'
} else if (block.name === 'global-analysis-charts') {
component = 'Charts'
} else if (block.name === 'global-analysis-table') {
component = 'Table'
} else {
return
}
children.push(createElement(component, { props: { data: block.data } }))
})
//将模块放入定位层
const positionContainer = createElement(
'div',
{ style: this.positionStyle, class: 'container-position', ref: 'position' },
children
)
//将定位层放入遮罩层并返回
return createElement(
'div',
{ style: this.hiddenStyle, class: 'container-hidden', ref: 'hidden' },
[positionContainer]
)
}
}
</script>
其中createElement可以接收三个参数,第一个为所创建的html元素,第二个为相关属性的数据对象,第三个为子节点。
具体教程可参考官方文档:渲染函数 & JSX