关于vue3 局部打印功能遇到的问题,到最后怎么实现的!!!

最近一个业务,要实现局部打印功能,原本我用三个"el-row"标签写了两行内容一个数据表格。首先尝试了, window.print(),可想而知是失败的,直接打印了全部网页,获取局部的代码没有样式。依次尝试了其他插架比如说:print-js、vue3-print-nb都不适用,不是说插件不行,这些插件打印element写出来的页面样式,打印的时候多多少少都是有瑕疵的,要么表格显示不全,要么样式没有,我的解决方案是适用了原生的表格,代码如下。

改成原生表格

       <!-- 打印的内容 -->
      <div id="printContent" style="width: 100%" class="margin-top-15 report-font">
  <table cellspacing="0" border="1" style="width: 100%" class="margin-top-15 table-width-100">
          <tr>
            <td class="center bold" style="width: 5%" v-text="$t('report.number')"></td>
            <td class="center bold" style="width: 29%" v-text="$t('report.name')"></td>
            <td class="center bold" style="width: 18%" v-text="$t('report.lastYearFinalAccounts')"></td>
            <td class="center bold" style="width: 18%" v-text="$t('report.thisYearFinalAccountsDetail')"></td>
            <td class="center bold" style="width: 30%" v-text="$t('report.explain')"></td>
          </tr>
          <template v-if="tableData.length">
            <template v-for="(item, index) in tableData" :key="index">
              <tr class="table-width-100 report-row-height-20">
                <td class="center" style="width: 5%">{{ item.num }}</td>
                <td class="left" style="width: 29%" v-html="stringFormatter(item)"></td>
                <td class="left" style="width: 18%">
                  {{ amountFormatter(item.lastYearFinalAccounts) }}
                </td>
                <td class="left" style="width: 18%">{{amountFormatter(item.currentBudget)}}
                </td>
                <td class="left" style="width: 30%">{{ item.remark }}</td>
              </tr>
            </template>
          </template>
          <template v-else>
            <tr class="table-width-100 report-row-height-20">
              <td colspan="5" style="text-align: center;">
                暂无数据
              </td>
            </tr>
          </template>
        </table>
      </div>

这里有两种打印方案:首先最外层套了一个div设置了一个id为printContent的标签。

  1. 第一种:用iframe打印,页面也不会改变,也不用刷新,也不用重新打开页面。
    首先在template中加入一个隐藏的iframe
  <!--打印用的隐藏的iframe-->
  <iframe width="0" height="0" frameborder="0" id="printIframe"></iframe>

然后就做打印的处理函数

// 处理打印按钮点击事件
const handlePrint = () => {
  //判断表格是否有数据
  if (tableData.value.length === 0) {
    $message.warning(t('general.noData'))
    return
  }
  //因为TypeScript 强制执行更严格的空值检查。所以一些地方加了?或者判断
  //获取打印内容
  const printHtml = document?.getElementById("printContent")?.innerHTML;
  //获取iframe 标签
  const syfPrint = document?.getElementById("printIframe") as HTMLIFrameElement | null;

  if (syfPrint) {
  //获取原页面里的head标签
    const documentHead = document.getElementsByTagName("head")[0];
      //获取iframe 页面里的head标签
    const iframeHead = syfPrint.contentDocument?.getElementsByTagName("head")[0];
	//把原页面的里的head标签内容给到iframe 页面里的head
    if (iframeHead) {
      iframeHead.innerHTML = documentHead.innerHTML;
    }
	//获取iframe 页面里的body,然后把dom结构赋值给iframe 
    const syfPrintBody = syfPrint.contentDocument?.body;
    if (syfPrintBody) {
      syfPrintBody.innerHTML = printHtml || "";
      //执行打印
      syfPrint.contentDocument.execCommand("Print");
    }
  } else {
  //错误提示
    $message.error(t('general.link.error'))
  }
}

这种方式直接在本页面打印,没毛病。
2. 第二中新打开了一个标签页,代码如下:

// 处理打印按钮点击事件
const handlePrint = () => {
  //判断表格是否有数据
  if (tableData.value.length === 0) {
    $message.warning(t('general.noData'))
    return
  }
  //获取本页面样式
    const styles = Array.from(document.styleSheets)
        .map(sheet => Array.from(sheet.cssRules)
            .map(rule => rule.cssText)
            .join('\n'))
        .join('\n');

    // 创建一个新的窗口,以打开打印预览
    const printWindow = window.open('', '_blank');
    printWindow?.document.open();

    // 将当前页面的样式信息添加到新窗口中
    printWindow?.document.write(`
      <html>
        <head>
          <style>
            ${styles}
          </style>
        </head>
        <body>
           ${document?.getElementById("printContent")?.innerHTML}
        </body>
      </html>
    `);

    printWindow?.document.close();
    printWindow?.print();
}

当然,你用原生代码写的,完全可以使用插件,我这里还以我安装的vue3-print-nb为例,直接可以不写打印事件,只要一个打印按钮就行,如下:

  <el-button type="primary" :icon="Printer" v-print="'#printContent'">打印</el-button>

v-print="‘#printContent’"直接指定要打印的标签ID就可以了,其他插架没有尝试,有兴趣可以试试。

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FirstTalent

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值