我有很長的內容(圖像,列表,div,文本等多種內容...).我想把這些內容以虛擬PDF頁面的形式展示給用戶。我不想生成PDF,只是顯示這個HTML內容的頁面(由寬度/高度定義)具有相同的頁眉/頁腳。它應該看起來像下圖,正如你在第一頁看到的,我想分割文本,并顯示在下一頁:
我正在React上運行這個應用程序。我不知道這個內容會是什么,每個渲染都會不同(根據用戶活動的不同內容)。
你對此有什么建議嗎?(CSS解決方案,或JS,或我不知道也許有些反應庫...)
這是一個簡單但有效的實現。
我們的想法是將html安裝到一個屏幕外的div中,這個div與我們要呈現的頁面具有相同的尺寸。
然后迭代這個offscreen div的元素(即來自解析的html的子元素)并使用getBoundingClientRect查詢dom以找到第一個溢出的元素。
然后,我們從屏幕外div中移除溢出元素之前的所有元素,并將它們緩存在一個數組中。
重新開始一個新塊,直到屏幕外div中不再有元素。
將此改編為React只是對每個頁面的HTML內容使用dangerouslySetInnerHTML的問題。
(display flex只是為了強制元素流動,但是任何布局都可以,只要它在offscreenDiv和page中是相同的)
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>
作為對remix23的另一個回答的補充,我試圖在將html文檔轉換成pdf以打印在紙上之前,通過格式化html文檔來做一些類似的事情。我發現CSS格式是我的答案https://www . smashingmagazine . com/2015/01/designing-for-print-with-CSS/
我不確定這是否是您正在尋找的解決方案,但正在使用
<style>
@media print {
div { break-inside: avoid; }
}
</style>
這是我在瀏覽器中打開html文檔并使用其內置的ctrl-P來查看一個& quot虛擬PDF & quot。這個方法也讓我修改頁邊空白和指定紙張的寬度/高度。