栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

让Google Chrome浏览器在打印页面上重复表格标题

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

让Google Chrome浏览器在打印页面上重复表格标题

更新2017年3月22日:重复表头终于在Chrome中实现了!(实际上,我认为它们是在一段时间之前实现的。)这意味着您可能不再需要此解决方案。只需将列标题放在

<thead>
标签中就可以了。仅在以下情况下使用以下解决方案:

  • 您在Chrome的实施中遇到了令人眼花show乱的错误,
  • 您需要“额外功能”,或者
  • 您需要支持一些仍不支持重复标头的奇怪浏览器。

解决方案(已淘汰)

下面的代码演示了我发现的多页表格打印的最佳方法。它具有以下功能:

  • 列标题在每一页上重复
  • 无需担心纸张大小或可容纳多少行-浏览器会自动处理所有内容
  • 分页符仅在行之间发生
  • 单元格边界始终完全封闭
  • 如果在表格顶部附近发生分页符,它将不会留下没有数据的孤立标题或列标题(问题不仅限于Chrome)
  • 适用于Chrome!(以及其他基于Webkit的浏览器,例如Safari和Opera)

…以及以下已知限制:

  • 仅支持1 (无论如何,这显然是允许您拥有的最多)
  • 不支持(尽管在技术上可以兼容Chrome的运行页脚)
  • 仅支持顶部对齐
  • 桌子不能有顶部或底部margin; 要在表格上方或下方添加空白,请插入一个空div并在表格上设置一个底边距
  • 任何影响高度的CSS大小值(包括border-width和line-height)都必须位于px
  • 无法通过将宽度值应用于各个表格单元格来设置列宽;您应该让单元格内容自动确定列宽,或者s在需要时用于设置特定宽度

JS运行后,无法(轻松)动态更改表

编码

<!DOCTYPE html><html>  <body>    <table > <!-- Delete "t1" class to remove row numbers. -->      <caption>Print-Friendly Table</caption>      <thead>        <tr>          <th></th>          <th>Column Header</th>          <th>Column Header</th>          <th>Multi-Line<br/>Column<br/>Header</th>        </tr>      </thead>      <tbody>        <tr>          <td></td>          <td>data</td>          <td>Multiple<br/>lines of<br/>data</td>          <td>data</td>        </tr>      </tbody>    </table>  </body></html><style>      div.fauxRow {      display: inline-block;      vertical-align: top;      width: 100%;      page-break-inside: avoid;    }    table.fauxRow {border-spacing: 0;}    table.fauxRow > tbody > tr > td {      padding: 0;      overflow: hidden;    }    table.fauxRow > tbody > tr > td > table.print {      display: inline-table;      vertical-align: top;    }    table.fauxRow > tbody > tr > td > table.print > caption {caption-side: top;}    .noBreak {      float: right;      width: 100%;      visibility: hidden;    }    .noBreak:before, .noBreak:after {      display: block;      content: "";    }    .noBreak:after {margin-top: -594mm;}    .noBreak > div {      display: inline-block;      vertical-align: top;      width:100%;      page-break-inside: avoid;    }    table.print > tbody > tr {page-break-inside: avoid;}    table.print > tbody > .metricsRow > td {border-top: none !important;}          table.fauxRow, table.print {      font-size: 16px;      line-height: 20px;    }      body {counter-reset: t1;}     .noBreak .t1 > tbody > tr > :first-child:before {counter-increment: none;}     .t1 > tbody > tr > :first-child:before {       display: block;      text-align: right;      counter-increment: t1 1;      content: counter(t1);    }    table.fauxRow, table.print {      font-family: Tahoma, Verdana, Georgia;       margin: 0 auto 0 auto;     }    table.print {border-spacing: 0;}    table.print > * > tr > * {      border-right: 2px solid black;      border-bottom: 2px solid black;      padding: 0 5px 0 5px;    }    table.print > * > :first-child > * {border-top: 2px solid black;}    table.print > thead ~ * > :first-child > *, table.print > tbody ~ * > :first-child > * {border-top: none;}    table.print > * > tr > :first-child {border-left: 2px solid black;}    table.print > thead {vertical-align: bottom;}    table.print > thead > .borderRow > th {border-bottom: none;}    table.print > tbody {vertical-align: top;}    table.print > caption {font-weight: bold;}</style><script>  (function() { // THIS FUNCTION IS NOT REQUIRED. It just adds table rows for testing purposes.    var rowCount = 100      , tbod = document.querySelector("table.print > tbody")      , row = tbod.rows[0];    for(; --rowCount; tbod.appendChild(row.cloneNode(true)));  })();  (function() { // THIS FUNCTION IS REQUIRED.    if(/Firefox|MSIE |Trident/i.test(navigator.userAgent))      var formatForPrint = function(table) {        var noBreak = document.createElement("div")          , noBreakTable = noBreak.appendChild(document.createElement("div")).appendChild(table.cloneNode())          , tableParent = table.parentNode          , tableParts = table.children          , partCount = tableParts.length          , partNum = 0          , cell = table.querySelector("tbody > tr > td");        noBreak.className = "noBreak";        for(; partNum < partCount; partNum++) {          if(!/tbody/i.test(tableParts[partNum].tagName)) noBreakTable.appendChild(tableParts[partNum].cloneNode(true));        }        if(cell) {          noBreakTable.appendChild(cell.parentNode.parentNode.cloneNode()).appendChild(cell.parentNode.cloneNode(true));          if(!table.tHead) { var borderRow = document.createElement("tr"); borderRow.appendChild(document.createElement("th")).colSpan="1000"; borderRow.className = "borderRow"; table.insertBefore(document.createElement("thead"), table.tBodies[0]).appendChild(borderRow);          }        }        tableParent.insertBefore(document.createElement("div"), table).style.paddingTop = ".009px";        tableParent.insertBefore(noBreak, table);      };    else      var formatForPrint = function(table) {        var tableParent = table.parentNode          , cell = table.querySelector("tbody > tr > td");        if(cell) {          var topFauxRow = document.createElement("table") , fauxRowTable = topFauxRow.insertRow(0).insertCell(0).appendChild(table.cloneNode()) , colgroup = fauxRowTable.appendChild(document.createElement("colgroup")) , headerHider = document.createElement("div") , metricsRow = document.createElement("tr") , cells = cell.parentNode.cells , cellNum = cells.length , colCount = 0 , tbods = table.tBodies , tbodCount = tbods.length , tbodNum = 0 , tbod = tbods[0];          for(; cellNum--; colCount += cells[cellNum].colSpan);          for(cellNum = colCount; cellNum--; metricsRow.appendChild(document.createElement("td")).style.padding = 0);          cells = metricsRow.cells;          tbod.insertBefore(metricsRow, tbod.firstChild);          for(; ++cellNum < colCount; colgroup.appendChild(document.createElement("col")).style.width = cells[cellNum].offsetWidth + "px");          var borderWidth = metricsRow.offsetHeight;          metricsRow.className = "metricsRow";          borderWidth -= metricsRow.offsetHeight;          tbod.removeChild(metricsRow);          tableParent.insertBefore(topFauxRow, table).className = "fauxRow";          if(table.tHead) fauxRowTable.appendChild(table.tHead);          var fauxRow = topFauxRow.cloneNode(true) , fauxRowCell = fauxRow.rows[0].cells[0];          fauxRowCell.insertBefore(headerHider, fauxRowCell.firstChild).style.marginBottom = -fauxRowTable.offsetHeight - borderWidth + "px";          if(table.caption) fauxRowTable.insertBefore(table.caption, fauxRowTable.firstChild);          if(tbod.rows[0]) fauxRowTable.appendChild(tbod.cloneNode()).appendChild(tbod.rows[0]);          for(; tbodNum < tbodCount; tbodNum++) { tbod = tbods[tbodNum]; rows = tbod.rows; for(; rows[0]; tableParent.insertBefore(fauxRow.cloneNode(true), table).rows[0].cells[0].children[1].appendChild(tbod.cloneNode()).appendChild(rows[0]));          }          tableParent.removeChild(table);        }        else          tableParent.insertBefore(document.createElement("div"), table).appendChild(table).parentNode.className="fauxRow";      };    var tables = document.body.querySelectorAll("table.print")      , tableNum = tables.length;    for(; tableNum--; formatForPrint(tables[tableNum]));  })();</script>

它是如何工作的(如果您不在乎,请继续阅读;上面您需要的一切。)

根据@Kingsolmn的要求,以下说明了此解决方案的工作方式。它没有涵盖并不是严格要求的Javascript(尽管它确实使此技术更易于使用)。相反,它专注于生成的HTML结构和关联的CSS,这才是真正的魔术。

这是我们将要使用的表:

<table>  <tr><th>ColumnA</th><th>ColumnB</th></tr>  <tr><td>row1</td><td>row1</td></tr>  <tr><td>row2</td><td>row2</td></tr>  <tr><td>row3</td><td>row3</td></tr></table>

(为了节省空间,我只给了它3个数据行;显然,一个多页表通常会有更多行)

我们需要做的第一件事是将表拆分为一系列较小的表,每个表都有自己的列标题副本。我称这些较小的表为fauxRows。

<table> <!-- fauxRow -->  <tr><th>ColumnA</th><th>ColumnB</th></tr>  <tr><td>row1</td><td>row1</td></tr></table><table> <!-- fauxRow -->  <tr><th>ColumnA</th><th>ColumnB</th></tr>  <tr><td>row2</td><td>row2</td></tr></table><table> <!-- fauxRow -->  <tr><th>ColumnA</th><th>ColumnB</th></tr>  <tr><td>row3</td><td>row3</td></tr></table>

fauxRows本质上是原始表的克隆,但每个表仅包含一个数据行。(不过,如果您的表有标题,则只有顶部的fauxRow才应包含它。)

接下来,我们需要使fauxRows 牢不可破。这意味着什么?(请注意-这可能是分页符处理中最重要的概念。)“牢不可破”是我用来描述无法在两个页面之间分割的内容块的术语*。当在此类块所占据的空间内发生分页符时,整个块将移至下一页。(请注意,我在这里非正式地使用了“块”一词;我并不是专门指块级元素。)此行为有一个有趣的副作用,我们稍后会加以利用:它可以公开内容由于分层或溢出最初被隐藏。

通过应用以下两个CSS声明,我们可以使fauxRows坚不可摧:

page-break-inside: avoid;

display: inline-table;

我通常同时使用这两种方法,因为第一种是为此目的而制成的,第二种是在较旧/不兼容的浏览器中起作用的。不过,在这种情况下,为简单起见,我将坚持使用page-break属性。请注意,添加此属性后,您将看不到表格外观的任何变化。

<table > <!-- fauxRow -->      <tr><th>ColumnA</th><th>ColumnB</th></tr>      <tr><td>row1</td><td>row1</td></tr>    </table>    <table > <!-- fauxRow -->      <tr><th>ColumnA</th><th>ColumnB</th></tr>      <tr><td>row2</td><td>row2</td></tr>    </table>    <table > <!-- fauxRow -->      <tr><th>ColumnA</th><th>ColumnB</th></tr>      <tr><td>row3</td><td>row3</td></tr>    </table>

现在,fauxRows是不可破坏的,如果在数据行中发生了分页符,它将移至下一页及其附加的标题行。因此,下一页将始终在顶部具有列标题,这是我们的目标。但是,表现在看起来很奇怪,带有所有额外的标题行。为了使它再次看起来像一张普通表,我们需要隐藏额外的标题,使它们仅在需要时才会出现。

我们要做的是将每个fauxRow放入带有的容器元素中overflow: hidden;,然后将其向上移动,以使标头被容器的顶部剪裁。这还将把数据行移回一起,使它们看起来是连续的。

您的第一个直觉可能是对容器使用div,但是我们将改为使用父表的单元格。稍后我将解释原因,但现在,我们只添加代码。(再次,这不会影响表格的外观。)

table {  border-spacing: 0;  line-height: 20px;}th, td {  padding-top: 0;  padding-bottom: 0;}
<table> <!-- parent table -->  <tr>    <td >      <table > <!-- fauxRow -->        <tr><th>ColumnA</th><th>ColumnB</th></tr>        <tr><td>row1</td><td>row1</td></tr>      </table>    </td>  </tr>  <tr>    <td >      <table > <!-- fauxRow -->        <tr><th>ColumnA</th><th>ColumnB</th></tr>        <tr><td>row2</td><td>row2</td></tr>      </table>    </td>  </tr>  <tr>    <td >      <table > <!-- fauxRow -->        <tr><th>ColumnA</th><th>ColumnB</th></tr>        <tr><td>row3</td><td>row3</td></tr>      </table>    </td>  </tr></table>

请注意表格标记上方的CSS。我添加它的原因有两个:首先,它防止父表在fauxRows之间添加空白;其次,它使标头高度可预测,这是必需的,因为我们没有使用Javascript来动态地计算它。

现在我们只需要向上移动fauxRows,我们将使用负边距进行处理。但这并不像您想的那么简单。如果我们直接向fauxRow添加负边距,则当fauxRow碰到下一页时,它将保持有效,从而导致页眉被页面顶部裁剪。我们需要一种方法来消除负利润。

为此,我们将在每个fauxRow的第一个之后插入一个空的div,并向其添加负边距。(第一个fauxRow会被跳过,因为它的标题应该始终可见。)由于页边距在单独的元素上,因此它不会跟随fauxRow到下一页,并且标题也不会被剪切。我称这些为空的divs headerHiders。

table {  border-spacing: 0;  line-height: 20px;}th, td {  padding-top: 0;  padding-bottom: 0;}
<table> <!-- parent table -->  <tr>    <td >      <table > <!-- fauxRow -->        <tr><th>ColumnA</th><th>ColumnB</th></tr>        <tr><td>row1</td><td>row1</td></tr>      </table>    </td>  </tr>  <tr>    <td >      <div ></div> <!-- headerHider -->      <table > <!-- fauxRow -->        <tr><th>ColumnA</th><th>ColumnB</th></tr>        <tr><td>row2</td><td>row2</td></tr>      </table>    </td>  </tr>  <tr>    <td >      <div ></div> <!-- headerHider -->      <table > <!-- fauxRow -->        <tr><th>ColumnA</th><th>ColumnB</th></tr>        <tr><td>row3</td><td>row3</td></tr>      </table>    </td>  </tr></table>

运行代码段展开摘要
就是这样,我们完成了!在屏幕上,该表现在看起来应该是正常的,顶部只有一组列标题。在打印中,它现在应该具有正在运行的标题。

如果您想知道为什么我们使用父表而不是一堆容器div,那是因为Chrome / webkit有一个错误,该错误会导致div封闭的不可破坏块将其容器携带到下一页。由于headerHider也位于容器中,因此不会像预期的那样被遗忘,这会导致标题被剪切。仅当不可破坏的块是div中具有最高非零高度的元素中的最高元素时,才会发生此错误。

在编写本教程时,我确实发现了一种解决方法:您只需要height: 0;在headerHider上进行显式设置,并为其提供一个非零高度的空子div。然后,您可以使用div容器。不过,我仍然更喜欢使用父表,因为它已经过更彻底的测试,并且通过将fauxRows绑回到一个表中,在某种程度上可以挽救语义。

编辑:我刚刚意识到Javascript生成的标记稍有不同,因为它将每个fauxRow放在单独的容器表中,并为其分配“ fauxRow” className(容器)。这是页脚支持所必需的,我打算有一天要添加它,但从未这样做。如果要更新JS,我可能会考虑切换到div容器,因为使用表的语义理由不适用。

*
在一种情况下,不可破坏的块可以分为两页:当它超出可打印区域的高度时。您应该尝试避免这种情况;实际上,您是在要求浏览器执行不可能的事情,并且它会对输出产生一些非常奇怪的影响。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/635258.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号