vue 表格分页打印,字体自适应大小缩放。

目录

一、需求背景

二、实现思路

三、缩放逻辑代码

四、页面使用

五、打印时注意事项

六、v-print打印


一、需求背景

表格数据需要分页打印预览,1页固定10条,每一页下面都要有一行领导签字。因表格内字数不确定,1页强制10行,有的页面很短,有的页面会超出,效果不好,需要每个单元格内大小自适应表格调整。

最终效果如下:



二、实现思路

通过计算每个单元格的大小、可容纳的文字数量与实际的文字数量的比例来动态控制每个单元格内文字的缩放比例。

相关计算公式:

(1) 计算每个单元格容纳的标准字体个数

(单元格长度 x 单元格高度)÷ ( 字体大小²  x  行高)=  可能容纳最多的字数

单元格内字数如果超过可能容纳最多的字数,那么字体需要缩小,如果不超过,那么不需要缩小。

(2)需要缩小的字体大小计算方式

(单元格长度 x 单元格高度)÷ ( 实际字数 x  行高)=  字体大小²

如果字体大小超过默认字体大小,不需要改变,如果小于默认字体大小就是需要缩小的。

(3)同时要注意,字母,数字,英文标点符号,占的比例应该为字体的0.6倍左右,需要处理。



三、缩放逻辑代码

tableScale.js
默认字体为14px



export const tableScale = {
  methods: {
    tableScale(dom,theight) {
      function countSymbols(str) {
        let count = 0;
        for (let i = 0; i < str.length; i++) {
          const charCode = str.charCodeAt(i);
          // 判断是否为大小写字母
          if ((charCode >= 65 && charCode <= 90) || (charCode >= 97 && charCode <= 122)) {
            count++;
          } else if (charCode >= 48 && charCode <= 57) { // 判断是否为数字
            count++;
          } else if (charCode === 46 || charCode === 44 || charCode === 32) { // 判断是否为点(.)、逗号(,)或空格
            count++;
          }
        }
        return count;
      }
      $(dom).each(function () {
        let width = $(this).width();
        let height = theight;
        let text = $(this).text();
        let specialCount = countSymbols(text)
        let wordCount = text.length - (specialCount * 0.4)
        let fontPx = 14;
        //未缩放前的td高度如果大于标准高度,需要缩放
        if ($(this).height() > theight+2 && wordCount > 0) {
          //需要缩小的字体大小计算方式
          fontPx = Math.sqrt((width * height) / (wordCount * 1.5))
          if (fontPx > 14) {
            fontPx = 14
          }
          $(this).css('fontSize', fontPx + 'px')
        }
      });
      $(dom).each(function () {
        let height = $(this).height();
        let width = $(this).width();
        let text = $(this).text();
        let fontPxU = $(this).context.style.fontSize
        let fontPx = fontPxU == '' ? 0 : fontPxU.slice(0, fontPxU.length - 2);
        let specialCount = countSymbols(text)
        let wordCount = text.length - (specialCount * 0.4)
        //第一次缩放后,有误差,有的字体依然偏大,二次处理
        //td高度如果大于标准高度,需要缩放
        if (height > theight+2 && wordCount > 0) {
          //计算计算每个单元格容纳的标准字体个数
          let wordCountMax = (width * theight) / (fontPx * fontPx * 1.5)
          //容纳的标准字体个数<实际字体个数,需要再次缩小
          if (wordCountMax - 2 < wordCount) {
            if (fontPx > 10) {
              let scalFontPx = Math.round(fontPx) - 2;
              $(this).css('fontSize', scalFontPx + 'px');
            } else {
              let scalFontPx2 = Math.round(fontPx) - 1
              $(this).css('fontSize', scalFontPx2 + 'px')
            }
          }
        }
      })
    }
  }
}

四、页面使用


1.在vue2框架里面,上面代码是mixins的js,使用混入的方式引入

import { tableScale } from '@/mixins/tableScale.js';
mixins:[tableScale],

等表格数据赋值之后,开始渲染
第一个参数为你要渲染的表格td元素,第二个参数为表格高度px

  this.$nextTick(()=>{
       this.tableScale('#equipmentPrint .table  td',50)
  )

这样表格里面的字体就能缩放了。


五、打印时注意事项


端打印组件的原理都是将页面整理成理想样式,然后再打印。为了保证页面写的html样式和打印后一致。表格的宽度需要固定,我这用1000px刚好,具体可以自己微调。

注意点1:表格td的宽度要固定,加起来要刚好1000px。
注意点2:表格在打印区域内居中显示,保证打印效果 margin:0 auto;
注意点3:打印边距设置

<style scoped>
@page {
  margin: 1cm 0cm !important;
  size: landscape; //横向打印
}
</style>

注意点4:我这利用a-table,最后一列打印出来总会少半个字,不知道为什么被压缩了,最后一列可以设置一个padding-right保证打印效果

//解决最后一列打印后会被挤压短的问题
 .ant-table-small.ant-table-bordered .ant-table-thead > tr > th.ant-table-row-cell-last, .ant-table-small.ant-table-bordered .ant-table-tbody > tr > td:last-child {
    border-right: none;
    padding-right:10px !important;
}

六、v-print打印


打印区域加id    打印按钮加v-print="'#id '"

<template>
      <div id="equipmentPrint" class="archiveTable">
          <div>
            <div v-for="(itemList, indexList) in tableList" :key="indexList" style="page-break-after: always">
            <h2 style="text-align: center">分页打印表格数据</h2>
            <div class="tableRow">
              <a-table
                ref="table"
                size="small"
                rowKey="equipmentId"
                bordered
                :columns="columns"
                :dataSource="itemList"
                :pagination="false"
                :footer="handleFooterShow"
                class="table"
                style="width:1000px"
              >
              </a-table>
            </div>
            <div style="width: 100%; margin-top: 20px; display: flex">
              <div style="width: 50%; position: relative">
                <span style="font-weight: bold">组长:</span>
              </div>
              <div style="width: 50%; position: relative">
                <span style="font-weight: bold">部门领导:</span>
              </div>
            </div>
          </div>
        </div>
      </div>
</template>

<script>
import { tableScale } from '@/mixins/tableScale.js';
export default {
  name: 'equipmentPrint',
  mixins:[tableScale],
  components: {},
  data() {
    return {
      // 表头
      columns: [
        // 每次翻页后序号连续自增
        {
          title: 'xx',
          dataIndex: 'sortNum',
          key: 'sortNum',
          align: 'center',
          width: 55,
          customRender: (text, record) => {
            return record.sortNum
          },
        },
        {
          title: 'xx',
          align: 'center',
          dataIndex: 'equipmentName',
          width: 200,
        },
        {
          title: 'xx',
          align: 'center',
          dataIndex: 'equipmentNo',
          width: 150,
        },
        {
          title: 'xx',
          align: 'center',
          dataIndex: 'unitMeasurementName',
          width: 50,
        },
        {
          title: 'xx',
          align: 'center',
          dataIndex: 'rowNum',
          width: 50,
        },
        {
          title: 'xx',
          align: 'center',
          dataIndex: 'annex',
          width: 250,
        },
        {
          title: 'xx',
          align: 'center',
          dataIndex: 'remark',
          width: 245,
        }
      ],
      data: '接口数据对象数组',
      tableList: [],
    }
  },
  created() {},
  mounted() {
    //将数据改成二维数组,用于分页展示
    this.formatData()
  },
  methods: {
    handleFooterShow() {
      return <div>汇总:</div>
    },
    formatData() {
      this.data.forEach((item,index) =>{
        this.$set(item,'sortNum',index+1)
      })
      let count = this.handleTotal(this.data.length),
        len = this.data.length,
        chunk = 10
      for (let i = len; i < 10; i++) {
        //默认每页10行,空的也展示
        // for(let i = len; i < count; i++) {
        this.data.push({})
      }
      for (let i = 0; i < len; i += chunk) {
        this.tableList.push(this.data.slice(i, i + chunk))
      }
      console.log('打印的二位数组this.tableList', this.tableList)
      this.$nextTick(()=>{
        this.tableScale('#equipmentPrint .table  td',50)
        this.$emit('success',true)
      })
      
    },
  },
}
</script>

<style lang="less">

.archiveTable {
  width: 1020px;
  padding:0 5px;
  margin:0 auto;
  .ant-table-bordered .ant-table-tbody > tr > td {
    height: 50px !important;
    font-size:14px;
  }
  //解决最后一列打印后会被挤压短的问题
 .ant-table-small.ant-table-bordered .ant-table-thead > tr > th.ant-table-row-cell-last, 
 .ant-table-small.ant-table-bordered .ant-table-tbody > tr > td:last-child {
    border-right: none;
    padding-right:10px !important;
  }
  //避免出现横向滚动轴
  .ant-table-content{
    overflow-x: hidden;
  }
}
</style>
<style scoped>
@page {
  margin: 1cm 0cm !important;
  size: landscape; 
}
</style>

猜你喜欢

转载自blog.csdn.net/weixin_40992252/article/details/138216559