此处是vue项目中的用法,也可以改写,不使用vue的语法,也可以实现其他框架使用

window.print()

直接调用默认打印,设置打印时样式

  1. @media print {
  2. @page {
  3. margin: 0.5cm;
  4. }
  5. }

普通打印

打印分页表格时,可以实现各分页分别都展示表头。有高度限制,超出了就不展示表头(各浏览器不同)

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>打印测试</title>
  8. <script src="https://unpkg.com/vue@next"></script>
  9. <style>
  10. table {
  11. font-size: 12px;
  12. width: 100%;
  13. font-size: 9pt;
  14. border-collapse: collapse;
  15. border-spacing: 0;
  16. }
  17. tr {
  18. page-break-inside: avoid;
  19. }
  20. td {
  21. border: 1px solid #ccc;
  22. text-align: center;
  23. height: 36px;
  24. }
  25. </style>
  26. </head>
  27. <body>
  28. <div id="demo">
  29. <table>
  30. <thead style="display:table-header-group;font-weight:bold">
  31. <tr>
  32. <td colspan="2" align="center" style="font-weight:bold;border:3px double red">每页都有的表头</td>
  33. </tr>
  34. </thead>
  35. <tbody>
  36. <tr v-for="(item,index) in list">
  37. <td>{{item.a+index}}</td>
  38. <td>{{item.b+index}}</td>
  39. </tr>
  40. </tbody>
  41. <tfoot style="display:table-footer-group;font-weight:bold">
  42. <tr>
  43. <td colspan="2" align="center" style="font-weight:bold;border:3px double blue">每页都有的表尾</td>
  44. </tr>
  45. </tfoot>
  46. </table>
  47. </div>
  48. <script>
  49. const DEMO = {
  50. data() {
  51. return {
  52. list: []
  53. }
  54. },
  55. mounted() {
  56. this.list = new Array(50).fill({ a: 1, b: 10 })
  57. this.$nextTick(() => {
  58. window.print()
  59. })
  60. },
  61. methods: {
  62. }
  63. }
  64. Vue.createApp(DEMO).mount('#demo')
  65. </script>
  66. </body>
  67. </html>

根据表头自动计算打印分页

实现功能:动态表头,计算打印数据
注意:

  1. 在使用方法时,需要在打印时,将打印纸的宽高确定,在样式表设置打印的width,height

this.$uDeepClone 深克隆方法
this.$pluc cm、px转换方法

  1. /**
  2. * 实现打印表头分页
  3. * 前提:表格结构
  4. * index 为外层循环的index
  5. * A4纸打印 21cm*29.7cm
  6. *
  7. * <table>
  8. * <thead :ref="'thead' + index"></thead>
  9. * <tbody :ref="'tbody' + index">
  10. * <tr :ref="'tr' + index"></tr> //分割的数组
  11. * </tbody>
  12. * </table>
  13. *
  14. * @param {Array} parentData 打印数据
  15. * @param {String} name 切分循环的数据
  16. */
  17. export default {
  18. methods: {
  19. // 重写打印页面 根据改变打印数据 printData.tableList 实现
  20. calcPrintRender(parentData, name) {
  21. let footH = 30 //最后一行高度
  22. let pageH = this.$pluc.cm2px(29.7) - footH // 计算px
  23. let newPrintData = this.$uDeepClone(parentData) //重写数据
  24. newPrintData = newPrintData.map((v, i) => {
  25. v.symbol = i //添加标识位
  26. v.paging = '1/1'
  27. return v
  28. })
  29. for (let pI in parentData) {
  30. let item = parentData[pI]
  31. let detailArr = item[name]
  32. let thead = this.$refs[`thead${pI}`][0]
  33. let tbody = this.$refs[`tbody${pI}`][0]
  34. let tr = this.$refs[`tr${pI}`]
  35. if (thead && tbody && tr) {
  36. let theadH = thead.offsetHeight //头部高度
  37. let renderBody = pageH - theadH
  38. if (theadH > pageH) {
  39. continue
  40. }
  41. let tbodyH = tbody.offsetHeight
  42. console.log('pageH, theadH, tbodyH,renderBody', pageH, theadH, tbodyH, renderBody)
  43. // tr总高度
  44. let trTotal = tr.reduce((prev, next) => {
  45. console.log(next.offsetHeight)
  46. return prev + next.offsetHeight
  47. }, 0)
  48. // console.log(' trTotal', trTotal)
  49. if (theadH + tbodyH < pageH) {
  50. // 不做处理
  51. continue
  52. }
  53. // 获取渲染函数
  54. let sliceArr = this.deepRenderTr({ tr, renderBody, trTotal })
  55. // console.log('sliceArr', sliceArr)
  56. for (let newI in newPrintData) {
  57. let newItem = newPrintData[newI]
  58. if (newItem.symbol == pI) {
  59. let len = sliceArr.length
  60. if (len > 0) {
  61. let newArr = []
  62. sliceArr.forEach((v, i) => {
  63. let obj = this.$uDeepClone(item)
  64. if (i == 0) {
  65. obj[name] = detailArr.slice(0, v)
  66. } else {
  67. obj[name] = detailArr.slice(sliceArr[i - 1], v)
  68. }
  69. obj.paging = `${i + 1}/${len + 1}`
  70. newArr.push(obj)
  71. })
  72. // 推送最后一组数据
  73. let nObj = this.$uDeepClone(item)
  74. let last = sliceArr[len - 1] - detailArr.length
  75. nObj[name] = detailArr.slice(last)
  76. nObj.paging = `${len + 1}/${len + 1}`
  77. newArr.push(nObj)
  78. newPrintData.splice(newI, 1, ...newArr)
  79. }
  80. }
  81. }
  82. }
  83. }
  84. // console.log('new', newPrintData)
  85. return newPrintData
  86. },
  87. // 获取哪些tr需要截取
  88. deepRenderTr({ arr = [], tr, renderBody, trTotal }) {
  89. // 找到第一页 最后 tr的index 暂不考虑表头占满情况
  90. // console.log(arr, tr.length, renderBody, trTotal)
  91. let trSum = 0
  92. let firstPageIndex = null
  93. for (let trI in tr) {
  94. trSum += tr[trI].offsetHeight
  95. if (trSum >= renderBody) {
  96. firstPageIndex = trI - 1
  97. break
  98. }
  99. }
  100. if (firstPageIndex === null) {
  101. return arr
  102. } else {
  103. // 计算剩余高度
  104. let restH = trTotal - trSum + tr[firstPageIndex + 1].offsetHeight
  105. if (arr.length > 0) {
  106. let n = firstPageIndex + arr[arr.length - 1]
  107. arr.push(n)
  108. } else {
  109. arr.push(firstPageIndex)
  110. }
  111. if (restH < renderBody) {
  112. return arr
  113. } else {
  114. let newTr = tr.slice(firstPageIndex + 1, tr.length)
  115. let param = { arr: arr, tr: newTr, renderBody: renderBody, trTotal: restH }
  116. return this.deepRenderTr(param)
  117. }
  118. }
  119. },
  120. },
  121. }

cm与px的转换

  1. var ratio = 0
  2. pluc()
  3. export default {
  4. px2cm: function(px) {
  5. return Math.floor((px * 10) / ratio) / 10
  6. },
  7. px2mn: function(px) {
  8. var r = ratio / 10
  9. return Math.floor(px / r)
  10. },
  11. cm2px: function(cm) {
  12. return Math.floor(cm * ratio)
  13. },
  14. mm2px: function(mm) {
  15. var r = ratio / 10
  16. return Math.floor(mm * r)
  17. },
  18. }
  19. function pluc() {
  20. 'use strict'
  21. var div = document.createElement('div')
  22. div.style.width = '1cm'
  23. div.id = 'puc'
  24. document.body.appendChild(div)
  25. var w = getComputedStyle(div, null).width
  26. ratio = w.substr(0, w.length - 2)
  27. div.parentNode.removeChild(div)
  28. }