将HTML拆分为虚拟页面

时间:2019-03-04 09:39:26

标签: html css reactjs

我的内容很长(包含图片,列表,div,文本等的多个内容)。我想将此内容显示为虚拟PDF页面。我不想生成PDF,只需将此HTML内容显示为具有相同页眉/页脚的页面(由宽度/高度定义)即可。它的外观如下图所示,就像您在首页上看到的那样,我想拆分该文本并在下一页中显示:

VS debugging settings

我正在React上使用此应用程序。我不知道该内容将是什么,每个渲染都将有所不同(根据用户活动,其内容将有所不同)。

您对此有何建议? (CSS解决方案或JS,或者我不知道可能有一些React lib ...)

1 个答案:

答案 0 :(得分:2)

这是一个幼稚但可行的实现。

想法是将html挂载到屏幕外的div中,该div的尺寸与我们尝试呈现的页面的尺寸相同。

然后遍历此屏幕外div的元素(即,来自解析的html的children),并使用getBoundingClientRect查询dom,以查找第一个溢出元素。

然后,我们将所有元素从屏幕div上移除,然后将其缓存在数组中。

重新开始一个新的块,直到屏幕外的div中不再有任何元素。

使其适应于React只需在每个页面的html内容中使用dangerouslySetInnerHTML

(显示柔韧性仅用于强制元素流动,但是只要在offscreenDiv和页面中相同,任何布局都可以做到)

function generateRandomContent() {
  var alph = "abcdefghijklmnopqrstuvwxyz";
  var content = "";
  // we will generate 100 random elements displaying their index to keep track of what's happening
  for (var i = 0; i < 100; i++) {
    var type = parseInt(Math.random() * 2, 10);
    switch (type) {
      case 0: // text, generates and random p block
        content = content + "<p>" + i + " ";
        var numWords = 10 + parseInt(Math.random() * 50, 10);
        for (var j = 0; j < numWords; j++) {
          var numLetters = 2 + parseInt(Math.random() * 15, 10);
          if (j > 0) {
            content = content + " ";
          }
          for (var k = 0; k < numLetters; k++) {
            content = content + alph[parseInt(Math.random() * 26, 10)];
          }
          
        }
        content = content + "</p>";
        break;
      case 1: // colored div, generates a div of random size and color
        var width = 30 + parseInt(Math.random() * 20, 10) * 10;
        var height = 30 + parseInt(Math.random() * 20, 10) * 10;
        var color = "rgb(" + parseInt(Math.random() * 255, 10) + ", " + parseInt(Math.random() * 255, 10) + ", " + parseInt(Math.random() * 255, 10) + ")";
        content = content + '<div style="width: ' + width + 'px; height: ' + height + 'px; background-color: ' + color + '">' + i + '</div>';
        break;
       
    }
  }
  return content;
}

function getNodeChunks(htmlDocument) {
  var offscreenDiv = document.createElement('div');
  offscreenDiv.className = 'page';
  offscreenDiv.style.position = 'absolute';
  offscreenDiv.style.top = '-3000px';
  offscreenDiv.innerHTML = htmlDocument;
  offscreenDiv.display = 'flex';
  offscreenDiv.flexWrap = 'wrap';
  document.body.appendChild(offscreenDiv);
  offscreenRect = offscreenDiv.getBoundingClientRect();
  // console.log('offscreenRect:', offscreenRect);
  var chunks = [];
  var currentChunk = []
  for (var i = 0; i < offscreenDiv.children.length; i++) {
    var current = offscreenDiv.children[i];
    var currentRect = current.getBoundingClientRect();
    currentChunk.push(current);
    if (currentRect.bottom > (offscreenRect.bottom)) {
      // current element is overflowing offscreenDiv, remove it from current chunk
      currentChunk.pop();
      // remove all elements in currentChunk from offscreenDiv
      currentChunk.forEach(elem => elem.remove());
      // since children were removed from offscreenDiv, adjust i to start back at current eleme on next iteration
      i -= currentChunk.length;
      // push current completed chunk to the resulting chunklist
      chunks.push(currentChunk);
      // initialise new current chunk
      currentChunk = [current];
      offscreenRect = offscreenDiv.getBoundingClientRect();
    }
  }
  // currentChunk may not be empty but we need the last elements
  if (currentChunk.length > 0) {
    currentChunk.forEach(elem => elem.remove());
    chunks.push(currentChunk);
  }
  // offscreenDiv is not needed anymore
  offscreenDiv.remove();
  return chunks;
}

function appendChunksToPages(chunks) {
    var container = document.getElementsByClassName('root_container')[0];
    chunks.forEach((chunk, index) => {
      // ex of a page header
      var header = document.createElement('div');
      header.innerHTML = '<h4 style="margin: 5px">Page ' + (index + 1) + '</h4>';
      container.appendChild(header);
      var page = document.createElement('div');
      page.className = 'page';
      chunk.forEach(elem => page.appendChild(elem));
      container.appendChild(page);
    });
}

// generateRandom content outputs raw html, getNodeChunks returns
// an array of array of elements, the first dimension is the set of
// pages, the second dimension is the set of elements in each page
// finally appendChunks to pages generates a page for each chunk 
// and adds this page to the root container
appendChunksToPages(getNodeChunks(generateRandomContent()));
 
 .page {
  border: 1px solid;
  display: flex;
  flex-wrap: wrap;
  height: 700px;
  width: 50%;
  margin-bottom: 20px;
 }
<div class="root_container"></div>