此处是vue项目中的用法,也可以改写,不使用vue的语法,也可以实现其他框架使用
window.print()
直接调用默认打印,设置打印时样式
@media print {
@page {
margin: 0.5cm;
}
}
普通打印
打印分页表格时,可以实现各分页分别都展示表头。有高度限制,超出了就不展示表头(各浏览器不同)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>打印测试</title>
<script src="https://unpkg.com/vue@next"></script>
<style>
table {
font-size: 12px;
width: 100%;
font-size: 9pt;
border-collapse: collapse;
border-spacing: 0;
}
tr {
page-break-inside: avoid;
}
td {
border: 1px solid #ccc;
text-align: center;
height: 36px;
}
</style>
</head>
<body>
<div id="demo">
<table>
<thead style="display:table-header-group;font-weight:bold">
<tr>
<td colspan="2" align="center" style="font-weight:bold;border:3px double red">每页都有的表头</td>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in list">
<td>{{item.a+index}}</td>
<td>{{item.b+index}}</td>
</tr>
</tbody>
<tfoot style="display:table-footer-group;font-weight:bold">
<tr>
<td colspan="2" align="center" style="font-weight:bold;border:3px double blue">每页都有的表尾</td>
</tr>
</tfoot>
</table>
</div>
<script>
const DEMO = {
data() {
return {
list: []
}
},
mounted() {
this.list = new Array(50).fill({ a: 1, b: 10 })
this.$nextTick(() => {
window.print()
})
},
methods: {
}
}
Vue.createApp(DEMO).mount('#demo')
</script>
</body>
</html>
根据表头自动计算打印分页
实现功能:动态表头,计算打印数据
注意:
- 在使用方法时,需要在打印时,将打印纸的宽高确定,在样式表设置打印的width,height
this.$uDeepClone 深克隆方法
this.$pluc cm、px转换方法
/**
* 实现打印表头分页
* 前提:表格结构
* index 为外层循环的index
* A4纸打印 21cm*29.7cm
*
* <table>
* <thead :ref="'thead' + index"></thead>
* <tbody :ref="'tbody' + index">
* <tr :ref="'tr' + index"></tr> //分割的数组
* </tbody>
* </table>
*
* @param {Array} parentData 打印数据
* @param {String} name 切分循环的数据
*/
export default {
methods: {
// 重写打印页面 根据改变打印数据 printData.tableList 实现
calcPrintRender(parentData, name) {
let footH = 30 //最后一行高度
let pageH = this.$pluc.cm2px(29.7) - footH // 计算px
let newPrintData = this.$uDeepClone(parentData) //重写数据
newPrintData = newPrintData.map((v, i) => {
v.symbol = i //添加标识位
v.paging = '1/1'
return v
})
for (let pI in parentData) {
let item = parentData[pI]
let detailArr = item[name]
let thead = this.$refs[`thead${pI}`][0]
let tbody = this.$refs[`tbody${pI}`][0]
let tr = this.$refs[`tr${pI}`]
if (thead && tbody && tr) {
let theadH = thead.offsetHeight //头部高度
let renderBody = pageH - theadH
if (theadH > pageH) {
continue
}
let tbodyH = tbody.offsetHeight
console.log('pageH, theadH, tbodyH,renderBody', pageH, theadH, tbodyH, renderBody)
// tr总高度
let trTotal = tr.reduce((prev, next) => {
console.log(next.offsetHeight)
return prev + next.offsetHeight
}, 0)
// console.log(' trTotal', trTotal)
if (theadH + tbodyH < pageH) {
// 不做处理
continue
}
// 获取渲染函数
let sliceArr = this.deepRenderTr({ tr, renderBody, trTotal })
// console.log('sliceArr', sliceArr)
for (let newI in newPrintData) {
let newItem = newPrintData[newI]
if (newItem.symbol == pI) {
let len = sliceArr.length
if (len > 0) {
let newArr = []
sliceArr.forEach((v, i) => {
let obj = this.$uDeepClone(item)
if (i == 0) {
obj[name] = detailArr.slice(0, v)
} else {
obj[name] = detailArr.slice(sliceArr[i - 1], v)
}
obj.paging = `${i + 1}/${len + 1}`
newArr.push(obj)
})
// 推送最后一组数据
let nObj = this.$uDeepClone(item)
let last = sliceArr[len - 1] - detailArr.length
nObj[name] = detailArr.slice(last)
nObj.paging = `${len + 1}/${len + 1}`
newArr.push(nObj)
newPrintData.splice(newI, 1, ...newArr)
}
}
}
}
}
// console.log('new', newPrintData)
return newPrintData
},
// 获取哪些tr需要截取
deepRenderTr({ arr = [], tr, renderBody, trTotal }) {
// 找到第一页 最后 tr的index 暂不考虑表头占满情况
// console.log(arr, tr.length, renderBody, trTotal)
let trSum = 0
let firstPageIndex = null
for (let trI in tr) {
trSum += tr[trI].offsetHeight
if (trSum >= renderBody) {
firstPageIndex = trI - 1
break
}
}
if (firstPageIndex === null) {
return arr
} else {
// 计算剩余高度
let restH = trTotal - trSum + tr[firstPageIndex + 1].offsetHeight
if (arr.length > 0) {
let n = firstPageIndex + arr[arr.length - 1]
arr.push(n)
} else {
arr.push(firstPageIndex)
}
if (restH < renderBody) {
return arr
} else {
let newTr = tr.slice(firstPageIndex + 1, tr.length)
let param = { arr: arr, tr: newTr, renderBody: renderBody, trTotal: restH }
return this.deepRenderTr(param)
}
}
},
},
}
cm与px的转换
var ratio = 0
pluc()
export default {
px2cm: function(px) {
return Math.floor((px * 10) / ratio) / 10
},
px2mn: function(px) {
var r = ratio / 10
return Math.floor(px / r)
},
cm2px: function(cm) {
return Math.floor(cm * ratio)
},
mm2px: function(mm) {
var r = ratio / 10
return Math.floor(mm * r)
},
}
function pluc() {
'use strict'
var div = document.createElement('div')
div.style.width = '1cm'
div.id = 'puc'
document.body.appendChild(div)
var w = getComputedStyle(div, null).width
ratio = w.substr(0, w.length - 2)
div.parentNode.removeChild(div)
}