表格打印分页实践小结

阅读 444
收藏 27
2018-12-21
原文链接:damobing.com

前言

print作为浏览已经比较成熟的技术可以经常被用来打印页面的部分内容,我们可以在mdn上查看到mdn相关的简单介绍。

备注:juqery的print除了基本的打印之外,还可以控制一些基本的样式,标题,页眉页脚的设置等。

需求

本文主要介绍的不是以上的基本点,而是table在打印的时候,会因为一页无法承载而导致分页,然而我们并不知道分页之后的效果,当我们点击预览的时候才发现,原来一个整体的表格被分为了两个部分,而且还是同一行的被分割坏了。

那么产品无疑是希望体验升级的:
– 在页面查看时直接显示打印之后的效果,对于打印预览是有心里预期的,可以直接展示出什么位置会分页。所以我在代码设计上,直接为每个分页的部分直接变为新分割一个表格,然后通过页面的margin间距,在展示时就有分页的预期效果。

.m-print-table{
    &:not(:first-child){
        margin-top:10px
    }

}
  • 将print对于表格的分页进行代码设计,通过代码计算出当前页的空间是否还能放下当前行,如果可以那么显示并循环;如果不可以,计算本行内容的大小,进行计算分割出还可以放下几行内容,剩下的内容放到下一页。

常识

展示高度

页面的展示高度一般设置为950

ui页面 && 打印预览

ui页面的显示与打印预览的部分有较大的差别,并不是完全打印ui页面的效果。

  • 一般情况下,每行所承载的数据量和ui页面是不同的。

  • 一般情况下打印很多情况下需要分页,而ui上其实数据多页面也是连在一起的。

代码的设计原则

原本的页面模板

准备好进行按照预览规则拆分首先需要一个原来的表格模板,以及以后打印之后的容器模板。

为了简化模型,我这里只考虑两列,左边为数据项,右边为内容的表格。

// 要处理的原表格模板的所有tr
let trs = $('#demoTable').find('tr')
// 打印之后显示的table存放的容器
// 内容进行转换
let $container = $('#printContainer')

准备好分页的间隔模板

const tableHeader = '<table class="m-print-table-process"><tbody>'
const tableFooter = '</tbody></table><div class="pager"></div>'

分页符的样式

因为我的ui体验是设计页面展示时也进行相应的分页,所以没有加媒体查询,你可以去根据自己的需要决定是否需要加。

.pager{
    page-break-after:always;
}
@media print{
    //媒体查询样式
}

判断条件

// 是否是初始页 初始页可能会有一些抬头信息,比如下卖弄的81高度
let pageInit = true
// 默认的页面高度
let pageHeight = 950
// 初始化页面高度参数为0 不断累加
let initHeight = 0
// 计算当前页面的可用展示高度,每次进入新页面重新计算
let currentPageHeight = pageInit ? pageHeight - 81 : pageHeight;
// 获取当前行的高度
let height = idStr && (idStr === 'processList' || idStr === 'billList') ? this.getHeight(strArr) : 35

// 如果高度大于当前可展示高度 
if(initHeight >= currentPageHeight || (initHeight + height >= currentPageHeight){


}

区分的根据不同类型进行展示

  • 展示数据为数组的
// 特殊业务类型的
// 目前只考虑两页之内可以放下
// 获取分割后的数组 以及新的页面高度(传入当前行字符串,当前页面剩余可展示高度)
let {countArr, newPageHeight} = this.getSplitArr(strArr, currentPageHeight - initHeight)
countArr.map((item, index) => {
// 当前的继续追加到表格中 下一个重开表格
if (index === 0) {
    let tdStr = item.map(it => `${it}<br/>`).join('')
    tempHtml += `<tr><td>${typeStr}</td><td>${tdStr}</td></tr>`
} else if (index === 1) {
    if (item.length > 0) {
        tempHtml = tempHtml + tableFooter + tableHeader
        let tdStr = item.map(it => `${it}<br/>`).join('')
        tempHtml += `<tr><td>${typeStr}</td><td>${tdStr}</td></tr>`
    } 
    initHeight = newPageHeight
}
})
  • 展示数据为基本数据字符串类型的
tempHtml = tempHtml + tableFooter + tableHeader
tempHtml += `<tr>${trs[i].innerHTML}</tr>`
initHeight = initHeight - currentPageHeight + height
pageInit = false
  • 当前页还可以放下数据的,正常拼接
tempHtml += `<tr>${trs[i].innerHTML}</tr>`
initHeight += height

分割字符串数组的方法

其中计算高度的部分,40为经过试验后每行剩余可展示的科学可用的40个中文字符,而25位默认一行数据所需要的高度。

备注:这里我业务展示的数据是一个数组结构,如果你的是字符串结构要比我的判断简单很多。

经过这个方法将数据进行分割到两个数据后(countArr),前面的部分放到上一页,剩下的数据放到下一页,并计算出下一页还剩余的空间(newPageHeight),暂时没考虑第二页也放不下的情况。

   /**
     * @description 根据数组以及页面剩余高度,拆分数据数组
     * @param {Array} dataArr
     * @param {Number} remainHeight
     */
     getSplitArr(dataArr, remainHeight) {
         if (!dataArr || dataArr.length === 0) console.warn('数据为空')
         let getHeight = (data) => Math.ceil(data.length / 40) * 25
         let countArr = [[], []]
         let partIndex = 0 
         let totalHeight = remainHeight + 20
         let newPageHeight = dataArr.reduce((countHeight, item) => {
            countHeight += getHeight(item)
            if (countHeight < totalHeight) {
                countArr[partIndex].push(item)
            } else {
                totalHeight = 930
                countHeight = 0
                partIndex++
                countArr[partIndex].push(item)
            }
            return countHeight
         }, 0)
         return {countArr, newPageHeight}
     },

计算高度的方法

备注:仅供参考建议。+20为保留的每个tr行的上下padding.

getHeight(dataArr) {
    let getHeight = (data) => Math.ceil(data.length / 40) * 25
    return dataArr.reduce((countHeight, item) => {
            countHeight += getHeight(item)
            // console.log(countHeight)
            return countHeight 
        }, 0) + 20
    }

小结

以上是这次表格分页小小的实践,虽然浏览器打印整页已经技术非常成熟,但是根据产品需求进行指定的分页和一些数据的分割控制和显示还是需要一些代码设计的。

希望能帮助到你实现这部分需求的实现。

评论