我正在参加「掘金·启航计划」
项目需求
动态渲染PDF文件:
- 封面背景图不变,封面标题、二维码动态赋值;
- 内页内容:单双页样式不一样;表格行数的样式要做特别处理(难住我的点),元素未超过10项,则当前页平均分布,table每行高度自适应;如果超过10项,则所有内容项平均分布到N页,table每行高度自适应。
实现
前端做,主要是调取浏览器的打印功能window.print()API。
window.print函数默认打印整个页面,如果想要设置打印的内容和样式,需要用到@media print{},不需要打印的元素,class的样式为 display:none,然后再设置需要打印出来的class的样式。
引入打印样式的三种方式
在 CSS 中使用 @media print
@media print {
body {
background-color: #fff;
}
img {
visibility: hidden;
}
a::after {
content: "(" attr(href) ")"; /* 所有链接后显示链接地址 */
}
}
在 CSS 中使用 @import
@import url("my-print-style.css") print;
在 HTML 中使用 <link> 标签
<link rel="stylesheet" media="print" href="my-print-style.css">
在 @media print 或 my-print-style.css 中,可以自由的修改大部分样式。
注意,在预览的时候记得勾选这个选项。
处理数据源
- 获取到数据源之后,将每一列的内容项高度进行累加,如累加高度超过打印文档页的高度则进行切割,剩余的内容继续以上逻辑
- 通过高度计算,得知内容高度累加后的总的页数,然后把内容项 / 页数将内容进行切割,可以得到每一页中内容的行数,高度自适应的css关键是给table行增加样式:
height:auto
// 处理数据源
resolveData() {
let meals = this.pdfList.setMeals
let newMeals = []
meals.forEach((meal) => {
// 给表单每项内容添加序号
meal.sections.forEach((item, index) => {
item.orderNumber = index + 1
})
// 分别传入每个套餐的列表项、获取高度高的那个元素高度、返回的数组为一页
let obj = this.resolveHeight([], meal.sections) // 第一次分页处理
let number = obj.length // 单页的话、只返回一个originArr、多页返回 originArr, lastMeals
let results = this.spliceArr(meal.sections, number)
// 数组分成3等分
results.forEach((item, index) => {
let newMeal = JSON.parse(JSON.stringify(meal))
newMeal.sections = item
newMeals.push(newMeal)
})
})
this.setMeals = newMeals
}
/**
* 传入套餐列表项、计算高度、给列表做分割
* originArr
*/
resolveHeight(originArr, sections) {
let height = 0
let index = -1
// 获取需要分割的下标 用for
for (let i = 0; i < sections.length; i++) {
// 计算每一个项目的高度
height += this.getHeight(sections[i])
// 第一次大于 表格高度的时候 获取上个index index - 1 并且跳出循环
if (height > 610) {
// section 截取 index-1 之前的
index = i - 1
break
}
}
// index 不变 则返回当前 源数据 加 sectoins
if (index == -1) {
originArr.push(sections)
return originArr
} else {
originArr.push(sections.slice(0, index + 1)) // 第一页
let lastMeals = sections.slice(index + 1, sections.length) //除第一页外剩余所有
return this.resolveHeight(originArr, lastMeals)
}
}
/**
* 获取每一项元素内容、保留最高项的高度
*/
getHeight(data) {
let sectionNameHeight = Math.ceil(data.sectionName.length / 6) // A列行数
let sectionPurposeHeight = Math.ceil(data.sectionPurpose.length / 46) // B列行数
let max = Math.max(sectionNameHeight, sectionPurposeHeight)
return 10 + 14.4 * max
},
/**
* 分割一页 数据为几等份
*/
spliceArr(item, number) {
if (item.length == 0) {
return []
}
let index = Math.ceil(item.length / number)
let results = []
for (let i = 0; i < number; i++) {
let result = item.slice(0 + index * i, index + index * i)
results.push(result)
}
return results
}