前端实现PDF分页与Vue中的render函数

版权声明:本文为博主原创文章,如有错误欢迎指正,如需转载请注明出处,谢谢配合。 https://blog.csdn.net/xiaxiangyun/article/details/81117517

背景

提分加项目中遇到了一个需要前端对PDF页面进行分页的需求。该需求是要为每一位学生生成一份PDF的学习报告,起初是采用了前端提供几个页面模板,由java端调用iText去生成PDF,PDF的分页工作也由工具去完成。

但是由于页面中包含大量的数学公式、图片等一些对样式要求较高的元素,iText对很多CSS3属性的支持较差,生成的PDF经常会出现切页的情况。最后决定由前端生成分好页的页面,并提供一个方法导出当前页面的Dom节点,服务端通过访问该页面并调用此方法得到分页后的页面元素,最后调用Node的一个工具生成PDF。

而对于前端PDF分页的思路,大致分以下四步:

  1. 首先获取后台数据渲染页面
  2. 页面渲染好之后获取每个元素的高度,通过一定的算法判断各个元素应该在哪一页
  3. 对于跨页的元素,采用前页隐藏后页定位的模式,使之在视觉上刚好能接起来
  4. 完成分页

而在这个过程中因为每一页的元素是有分页后的数据所决定的,所以使用到了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

猜你喜欢

转载自blog.csdn.net/xiaxiangyun/article/details/81117517