之前写过一篇文章CSS实现自动分页打印同时每页保留重复的自定义内容,可以实现window.print()打印时多张页面保留相同的内容(如header、footer),但其并不是真正意义上的页眉页脚,footer内容在最后一张页面未撑满时不能置于页面底部。为了实现打印使用CSS自定义页眉页脚,解决之前遗留的问题,本文对之前的办法做了改进,提出了一种解决方案。

效果图

基本原理

  1. 在要打印的内容中,页眉页脚元素使用position: fixed,并设定各自的高度。
  2. 正文内容使用table元素,table的开头(thead)和结尾(tfoot)各使用一个设定高度(大于等于页眉页脚高度)的空DOM元素,防止页眉页脚与正文内容重叠。

此时即可实现自定义页眉页脚,调用window.print()时多张页面具有相同的页眉页脚,且页眉页脚可自定义内容,包括插入logo等图片。

示例代码

只打印指定dom内容,要打印的内容在#printDom中,页面在非打印模式不会显示其内容,只有在点击打印按钮调用window.print()时才会显示打印内容。

下方两个示例代码一样,根据个人阅读方式喜好查看。

示例代码-github:github

示例代码:

<html>
  <head>
    <title>print demo</title>
    <meta name="description" content="CSS打印,支持自定义页眉页脚" />
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
    <meta
      name="viewport"
      id="WebViewport"
      content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
    />
    <style>
      @media print {
        @page {
          size: A4 portrait;
          /* 调整页边距 */
          margin: 1cm 1cm 1cm;
        }

        #printDom {
          display: block !important;
        }
      }

      #printDom {
        /* 打印区域在非打印时不显示 */
        display: none;
        position: relative;
        font-size: 16px;
        font-family: SimSun, Songti SC;
      }

      #printDom .page-header {
        /* 页眉高度 */
        height: 2cm;
        display: flex;
        align-items: center;
        position: fixed;
        top: 0mm;
        width: 100%;
        border-bottom: 1px solid #ddd;
        z-index: 2000;
      }

      #printDom .page-header-space {
        /* 控制内容区距离顶部的距离,防止与页眉重叠 */
        height: 2cm;
      }

      #printDom .page-footer {
        /* 页脚高度 */
        height: 1cm;
        position: fixed;
        bottom: 0;
        width: 100%;
        border-top: 1px solid grey;
        z-index: 2000;
      }

      #printDom .page-footer-space {
        /* 控制内容区距离底部的距离,防止与页脚重叠 */
        height: 1.5cm;
      }

      #printDom > table {
        width: 100%;
      }
      
      #printDom .content table {
        width: 100%;
        font-size: 30px;
      }

      #printDom .content .header {
        text-align: center;
      }
    </style>
  </head>
  <body>
    <button onclick="handlePrint()">打 印</button>
    <div id="printDom">
      <!-- 页眉 -->
      <div class="page-header">Logo</div>
      <table>
        <!-- 占位,给页眉留出位置 -->
        <thead>
          <tr>
            <td><div class="page-header-space"></div></td>
          </tr>
        </thead>
        <!-- start: 正文 -->
        <tbody>
          <tr>
            <td>
              <div class="content">
                <!-- 正文的标题 -->
                <h1 class="header">H1</h1>
                <div>
                  <!-- 正文内容,可随意写,demo是表格 -->
                  <table>
                    <thead>
                      <tr>
                        <td>Index</td>
                        <td>Name</td>
                      </tr>
                    </thead>
                    <tbody id="tableBody">
                    </tbody>
                    <tfoot></tfoot>
                  </table>
                </div>
              </div>
            </td>
          </tr>
        </tbody>
        <!-- end: 正文 -->
        <!-- 占位,给页脚留出位置 -->
        <tfoot>
          <tr>
            <td><div class="page-footer-space"></div></td>
          </tr>
        </tfoot>
      </table>
      <!-- 页脚 -->
      <div class="page-footer">Footer</div>
    </div>

    <script>
      /**
       * 打印指定元素
       * @param {string} element 需要打印的元素选择器
       */
      function printElement(element) {
        var printContents = document.querySelector(element).cloneNode(true);
        
        var popupWin = window.open('', '_blank');
        popupWin.document.open();
        
        const styles = document.head.innerHTML;
        popupWin.document.write(`<html><head><title>Print Title</title>${styles}</head><body onload="window.print(); window.close();">`);
        popupWin.document.body.appendChild(printContents);
        popupWin.document.write('</body></html>');
        
        popupWin.document.close();
      }

      function handlePrint() {
        printElement('#printDom');
      }

      const tempTableData = document.querySelector('#tableBody');
      const tempFragument = document.createDocumentFragment();

      // mock data
      for (let i = 0; i < 30; i++) {
        const _tr = document.createElement('tr');
        const _td1 = document.createElement('td');
        _td1.appendChild(document.createTextNode(`No${i + 1}`));
        const _td2 = document.createElement('td');
        _td2.appendChild(document.createTextNode(new Date().getTime()));
        _tr.appendChild(_td1);
        _tr.appendChild(_td2);
        tempFragument.appendChild(_tr);
      }

      tempTableData.appendChild(tempFragument);
    </script>
  </body>
</html>

yotcap
11 声望1 粉丝

« 上一篇
ssh免密登录