每 X 行文本插入一个 HTML 元素分隔符的功能(动态分页,就像在专业文本编辑器中一样)

Function to insert a HTML element separator every X lines of text (dynamic pagination, just like in a professional text editor)

正在为开源项目编写响应式白皮书。

研究证明,这一挑战尚未被互联网上的任何人清楚地取消。

我的初衷是为每个页面创建一个完全响应的 A4 比例容器,并在每个页面元素中手动写入文本(这本身就是一个很好的挑战,我成功地使容器在任何屏幕上都是完美的比例, 但试图让文本在任何屏幕上看起来都一样似乎是不可能的), 所以我放弃了。

重要! 我记得我希望能够直接从 HTML 编辑白皮书的内容,并允许一个 JS 函数动态分离内容。否则,每次我想更改一页中的内容而文本不再适合时,我不得不再次手动重新编辑所有页面,在每一页中将所有内容向下或向上推,这很疯狂。

所以,现在我希望文本自动分页,就像您在 Word 等文本编辑器中编写时一样,只是您在编写 HTML 代码。

我在 HTML 中使用图像、iframe 和其他不寻常的元素这一事实带来了额外的困难,这意味着我无法使用 SVG 作为解决方案,这本来很容易。

现在。

我准备了这个代码笔让事情变得更容易: Responsive white paper (codepen)

所以我想做的是以某种方式在正确的位置插入一个中断,在我的例子中,断路器是:

</page><page>

使用 white-space: pre-line 或更好的方法,white-space: pre-wrap 似乎是让事情更容易编辑的明智的第一步。使用这个 CSS 可以让我检测到每行文本结束的确切位置。

然后,我不仅要考虑文本行,还要考虑图像、iframe 和其他类型的元素,我不知道它们的高度,因为它们是响应式的。

我的终极目标:

在正确的位置插入页面分隔元素,从原始 HTML 内容制作单独的页面,其中所有页面即使高度不同也大致相同。

可能的解决方案:

也许可以使用 splitText 函数?还是 ES6 的 split() 函数?我会努力的。

更新: 这个 与我需要的类似,但我目前似乎无法使其工作,将更新。

我最终成功完成了这项工作,我没有使用 </page><page> 作为断路器,因为我的 HTML 结构发生了一些变化,使事情变得更简单。

虽然性能还有很大提升空间!超级慢! 与问题相同的codepen:https://codepen.io/lucian_apetrei/pen/QWOvwzm

额外奖励! 是我设法创建了完美的 CSS calc 以在 A4 比例容器内创建完美的响应式内容,在任何屏幕,这本身就很酷,如果你想使用它,请随意!

HTML:

<div id="loader">Loading responsive white paper.<br><br><b>Please wait<br><hr><hr><hr></b></div>
<div id="white-paper">
<page id="page0">
    <content>
<h1 class="top0">The shift to a Biosphere Consciousness</h2>
        A new generation is rising and with it different views on how we define freedom, power, and community.
        There is a basic change going on with the younger generation that is strange to older people. There is a change in the way you define “freedom”, the way your define “power”, and the way you define “community”, and these changes really suggest the real revolution.

        For my generation and generations before me, freedom was very simple.

        To be free is to be an autonomous agent, to be self-sufficient, to be independent, to not be beholden to others, to be an island to oneself so that one can have freedom as exclusivity.
      
<iframe class="fullWidth" src="https://www.youtube-nocookie.com/embed/h5Krh2ZmZkk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>













        For the younger generation that grew up on the Internet, autonomy is death. Being “an island to oneself” is death. Because for your generation, you ask the question, “How can I flourish to the full extent of my possibilities here on the planet?” And it is clear that your answer to that is I flourish to the extent that I am embedded in community after community where I can share my talents and those talents can benefit the network and come back to benefit myself. I am free because I have access and for you, freedom is not exclusivity. It is inclusivity.
    
        The younger generation has a different sensibility about power which makes the older generation very nervous. We essentially have believed that power always has to be a pyramid. It goes from the top town. That is power. There is no other way to define power. It's a pyramid.
        But young people that grow up on the Internet - it's strange because you grew up thinking that power has to do with the networks you're engaged in. For you, power is not vertical, it's lateral. For you, power is being enmeshed in network after network where you benefit each other. Open source! 

<h2>And finally - I think most importantly</h2>
        We are seeing a change in the way our younger generation perceives identity to community. I grew up in a nation state - we were very clear on community - that is each individual is born to be an autonomous agent and we are each sovereign. And each of us compete with other sovereign individuals in the marketplace for scarce resources in a zero sum game. Our nations represent us because they are our sovereigns and they represent all the millions of individual citizens who are sovereigns against other nations and each nation then competes with every other nation for scarce resources in the marketplace or the battlefield in a zero sum game.
    
        Here's my question: Does anyone here believe that we are going to be able to address climate change and bring the human family together and take our responsibility for our fellow creatures and the Earth we live in with that worldview? Anybody?
        What we're beginning to see with our younger generation, and I don't want to overstretch this but I am beginning to sense a shift from geopolitics to biosphere consciousness. The biosphere is that nineteen kilometers from the stratosphere to the ocean where all life and all the chemicals on the planet interact to maintain the ecosystems and the biology of the Earth.
        These kids are learning ecological footprint. We actually have young people coming home and at dinner time they are asking their parents where the hamburger came from on the table. They are saying, “Did that hamburger come from a rainforest?” “Did they have to destroy the trees for four little inches of topsoil which only gives you three years of grazing so that cow could become my hamburger?” And when those trees are destroyed for the top soil to graze the cow for the hamburger, the kids are smart enough to understand that those trees harbor rare species of plant and animal life that only live in those canopies - they go extinct.

<img class="fullWidth" src="https://useruploads.socratic.org/VPqSrkhiSlmaLgJKbNZA_what-is-in-the-biosphere.png"> <xlines19xlines></xlines19xlines>       And then they connect the dots. If the trees disappear for the soil to graze the cow for the hamburger, those trees are not there to absorb carbon dioxide from industrial emissions and that means the temperature of the planet goes up. They are beginning to understand that everything each of us does intimately affects some other human being, some other creature and the planet we live in. We live in an indivisible, biosphere community. There is no escape. This isn't just academic. Our well-being depends on the well-being of the whole system and all the creatures in it.
            
        We all have to really come together. We've got one generation to lay down this new biosphere consciousness. Pass on this legacy so when your grandchildren look back at you, they can say you did the right thing. You helped replenish the planet, got us off carbon, and helped show our proper respect to generations not yet here including our fellow creatures.

        We must begin to think, organize, and act from a biosphere consciousness if life as we know it will continue to exist. We are in the midst of the greatest transition upon which humanity has ever embarked.
      
<h3>How will you respond?</h3>
    </content>
</page>
</div>

CSS:

html, body {background: #232323; margin: 0; padding: 0; height: 100%}
@import url('https://fonts.googleapis.com/css2?family=Dosis:wght@400;700&family=Roboto:wght@300;400;900&display=swap');
page {
  padding: 2em 2em 0 2em; /* these are my page margins */
  width: 69vw;
  height: calc(69vw * 1.4142); /* This is for setting up the white-paper container to be at A4 ratio on any screen */
  font-size: calc(69vw * 1.4142 / 54.0103); /* After days of tests and empty internet queries, I discovered the perfect font-size formula for responsive text on a A4 paper portrait ratio, on any screen, considering my above margins (padding); if you want to have smaller or bigger font sizes or for landscape ratios and margins, you also have to adjust the JavaScript variables */
  line-height: 1;
  font-family: Arial, sans-serif;
  margin: 0 auto 1em auto;
  background:#ffffff;
  overflow: hidden;
  position: relative;
  box-sizing: border-box;
  display: block
}

content {
  position: relative;
  display: inline;
  font-weight: 400;
  z-index: 12;
  font-size: 100%;
  line-height: 1.6;
  white-space: break-spaces;
  font-family: 'Roboto', Arial, sans-serif;
}

content h1, content h2, content h3, content h4 {
  margin: 0 !important;
  padding: 0 !important;
  font-size: 1em;
  font-weight: bold;
  display: inline
}

content h1 {display: flex; align-items: center; white-space: pre-wrap; background: #db463e; color: #ffffff; width: 69vw; height: 2em; position: absolute; left: -2em; text-transform: uppercase;}
content h1:before {content: ''; display: block; width: 1em; height: 1em; background: #ffffff; margin: 0 0.5em 0 1em;}

.top0 {top: -2.19em}

content h2 {font-size: 1.23em}
content h3 {font-size: 1.12em}

content img, content iframe {width: 100%;}
content iframe {height: calc(69vw * 0.5625)}
.fullWidth {width: 69vw; position: absolute; left: -2em}

content div {display: inline}

/* For Mobile */
@media screen and (max-width: 981px) and (orientation: portrait) {
  page {
    width: 100vw;
    height: calc(100vw * 1.4142); /* For Mobile */
    font-size: calc(100vw * 1.4142 / 54.0103); /* For Mobile */
  }
  .fullWidth, content h1 {width: 100vw;}
  content iframe {height: calc(100vw * 0.5625)}
}

#loader {text-align: center; font-size: 1em; width: 100vw; height: 100vh; background: rgba(0,0,0,.9); position: fixed; top: 0; z-index: 999; display: flex; justify-content: center; align-items: center; align-content: center; flex-direction: column; color: #ffffff; font-family: 'Roboto', Arial, sans-serif}
#loader b {font-size: 2em;}
#loader hr {display: inline-block; border: 0; width: 0.23em; height: 0.23em; background: #ffffff; margin: 0 0 0 0.23em; border-radius: 100%; animation: loaderDot 1.8s infinite ease-in-out}
#loader hr:nth-of-type(2) {animation-delay: 0.16s}
#loader hr:nth-of-type(3) {animation-delay: 0.32s}
@keyframes loaderDot {
  0% {transform: scale(1)}
  50% {transform: scale(0)}
  100% {transform: scale(1)}
}

JS:

// Get a single first matching element
var $ = function (selector, parent) {
  return (parent ? parent : document).querySelector(selector);
};

// Get all matching elements
var $$ = function (selector, parent) {
  return (parent ? parent : document).querySelectorAll(selector);
};

document.addEventListener("DOMContentLoaded", function () {
  var whitePaper = $('#white-paper');
  var container = $('#page0');
  var page0 = $('#page0 content');
  var parsedContent = new DOMParser().parseFromString(page0.innerHTML, 'text/html'); // first, we are parsing all content like paragraphs and all other elements into an array using DOMParser
  page0.innerHTML = ''; // let's Tabula Rasa so we can use the first page element to calculate each new addition into it

  var parsedArray = [...parsedContent.body.childNodes]
  .map(child => child.outerHTML || child.textContent);

  var currentPage = 0;
  var lastDiv = 0;
  var pageRects = 0;

  // a function to add the next page
  var addPage = function() {
    // add a new page
    var newPage = document.createElement('page');
    newPage.setAttribute("id", 'page' + currentPage);
    var emptyContent = document.createElement('content');
    newPage.appendChild(emptyContent);
    whitePaper.appendChild(newPage);
  }

  // a function to add each parsed item to the current page in a div or to remove the item if it doesn't fit at the end of the page
  var addRemoveItem = function(item, rects) {
    // if we don't have a manual override for pageRects, get the actual rects nr
    rects ? pageRects = rects : pageRects = $('#page' + currentPage + ' content').getClientRects().length;

    let previousDivContent;
    if (pageRects > 31) { // this will go through only once per new page
      let previousDiv = $('#page' + currentPage + ' content div:last-of-type');
      let previousDivId = previousDiv.id;
      previousDivContent = previousDiv.innerHTML;
      previousDiv.remove();
      currentPage++;
      addPage();
      $('#page'+currentPage+ ' content').innerHTML += '<div id="'+previousDivId+'">'+previousDivContent+'</div>'; // this is the first item on the next page
    }

    // if we have a new element or word / punctuation and the pageRects are smaller than 34, we add the new div ahead of the previous one
    var id = 'i' + lastDiv;
    lastDiv++;
    var newDiv = '<div id="'+id+'">'+item+'</div>';
    $('#page'+currentPage+ ' content').innerHTML += newDiv;

    // Debugging
    //console.log('Page Rects: ' + pageRects + ' | Item: ' + item + ' | Prev end item: ' + previousDivContent);
  }

  // let's loop through all the content parsed with DOMParser (paragraphs, links, headings, images, iframes)
  parsedArray.forEach((item, index) => {
    if (item.match(/<\/?[a-z][\s\S]*>/)) {
      // if the next item is an element
      if (item.match(/xlines/)) {
        let extraLines = item.split(/xlines/);
        let lines = extraLines[1];
        pageRects += parseInt(lines);
        addRemoveItem(item, pageRects);
      } else {
        addRemoveItem(item);
      }
    } else {
      // if the next item is a word / punctuation
      var words = item.split(' ');
      // loop through the words / punctuation
      words.forEach((item, i) => {
        addRemoveItem(item + ' ');
      });
    }
  });
  $('#loader').style.display = 'none';
});

重要提示: 在 HTML 中使用新行有效,但并非总是如此,在某些情况下,我不知道为什么,添加额外的行无法正常工作,您可以在我使用 [ 的第二张图像之后看到此错误=14=] 作为占位符,当我需要额外的行来正确推送内容时,手动 rects 计数覆盖。

要解决的问题: 如果有人知道如何让它运行得更快,请贡献!