本教程詳細介紹了如何使用javascript將網(wǎng)頁中的特定html元素(如收據(jù))打印到pdf或紙張。通過將目標元素的html內(nèi)容封裝為data uri并在新窗口中打開,結合內(nèi)聯(lián)javascript觸發(fā)自動打印,實現(xiàn)了一種高效且用戶友好的局部內(nèi)容打印解決方案,避免了復雜的內(nèi)容隱藏與恢復操作。
在構建復雜的網(wǎng)頁應用時,經(jīng)常會遇到需要打印頁面特定區(qū)域內(nèi)容的需求,例如電商網(wǎng)站的訂單收據(jù)、報告或證書。傳統(tǒng)的做法可能涉及通過JavaScript動態(tài)隱藏或顯示頁面元素,但這通常會導致頁面閃爍或復雜的DOM操作。本教程將介紹一種更為優(yōu)雅且自動化的方法,利用Data URI和內(nèi)聯(lián)JavaScript實現(xiàn)特定元素的打印功能。
本方案的核心在于以下幾個關鍵技術點:
首先,需要將你希望打印的特定內(nèi)容(例如收據(jù)表格)封裝在一個獨立的容器元素中。這樣做有助于JavaScript精確地獲取其HTML內(nèi)容。同時,為了打印時的樣式一致性,建議將與該內(nèi)容相關的CSS樣式直接嵌入到該容器內(nèi)部或其子元素中,以確保在新打開的打印頁面中樣式能夠正確應用。
以下是一個收據(jù)表格的HTML結構示例,它被包裹在一個 section 標簽內(nèi),并且其樣式直接嵌入在表格中:
立即學習“Java免費學習筆記(深入)”;
<section class="receipt-section"> <table class="receipt"> <style> /* 收據(jù)表格的專用樣式 */ .receipt { border-collapse: collapse; max-width: 80%; font-family: sans-serif; /* 初始樣式,打印時可能需要調(diào)整 */ } .receipt td { padding: .5em; } .receipt tr:nth-child(even) { border: 1px solid #333; border-inline: none; background: #ddd; } .receipt tr:nth-child(odd) { background: #fff } .header-Uprice, .item-Uprice, .header-qty, .item-qty { text-align: center } .total { border-bottom: 3px double #000 } </style> <tr class="table-headers"> <td class="header-id">#</td> <td class="header-desc">Item Description</td> <td class="header-Uprice">Unit Price</td> <td class="header-qty">Qty</td> <td class="header-price">Price</td> </tr> <tr class="item" id="1"> <td class="item-id">1</td> <td class="item-desc">Dummy Item1</td> <td class="item-Uprice">200$</td> <td class="item-qty">1</td> <td class="item-price">200$</td> </tr> <tr class="item" id="2"> <td class="item-id">2</td> <td class="item-desc">Dummy Item2</td> <td class="item-Uprice">75$</td> <td class="item-qty">1</td> <td class="item-price">75$</td> </tr> <tr class="item" id="3"> <td class="item-id">3</td> <td class="item-desc">Dummy Item3</td> <td class="item-Uprice">100$</td> <td class="item-qty">2</td> <td class="item-price">200$</td> </tr> <tr class="total"> <td>Total</td> <td></td> <td></td> <td></td> <td>475$</td> </tr> </table> </section>
接下來是實現(xiàn)打印功能的JavaScript代碼。我們將創(chuàng)建一個函數(shù),該函數(shù)在被調(diào)用時執(zhí)行以下操作:
獲取目標內(nèi)容并注入打印邏輯 首先,獲取包含收據(jù)的 table 元素。然后,向其內(nèi)部動態(tài)注入一個 <script> 標簽。這個腳本會在新頁面加載完成后執(zhí)行,首先應用一些額外的打印樣式(例如居中),然后調(diào)用 window.print() 觸發(fā)打印。
function printReceipt() { const receiptTable = document.querySelector('.receipt'); // 動態(tài)注入用于打印居中的CSS樣式,這里通過修改已有的style標簽實現(xiàn) // 注意:這里假設receiptTable內(nèi)部有一個<style>標簽,或者可以直接在receiptTable上添加style屬性 const cssCenteringScript = ` const styleTag = document.querySelector('table.receipt > style'); if (styleTag) { styleTag.innerHTML += '.receipt { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); margin: 0; }'; } else { // 如果沒有內(nèi)聯(lián)style標簽,則創(chuàng)建一個并注入 const newStyle = document.createElement('style'); newStyle.innerHTML = '.receipt { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); margin: 0; }'; document.head.appendChild(newStyle); } `; // 注入自動打印的腳本到收據(jù)表格內(nèi)容中 // 注意:這里將腳本直接添加到receiptTable的innerHTML,確保它在新頁面中被執(zhí)行 receiptTable.innerHTML += `<script>window.onload = () => { ${cssCenteringScript}; window.print(); }</script>`; // ... 后續(xù)步驟 }
構建 Data URI 在注入腳本后,獲取包含整個 section 的完整HTML內(nèi)容。然后,使用 encodeURIComponent 對這段HTML字符串進行編碼,并前綴 data:text/html, 來構建Data URI。
function printReceipt() { // ... (前面注入腳本的代碼) ... const receiptSectionHTML = document.querySelector('.receipt-section').innerHTML; const dataUri = 'data:text/html,' + encodeURIComponent(receiptSectionHTML); // ... 后續(xù)步驟 }
在新窗口中打開并觸發(fā)打印 最后,使用 window.open() 方法在新標簽頁或新窗口中打開這個Data URI。由于Data URI中包含了自動打印的腳本,新頁面加載后將立即彈出打印對話框。
function printReceipt() { const receiptTable = document.querySelector('.receipt'); const cssCenteringScript = ` const styleTag = document.querySelector('table.receipt > style'); if (styleTag) { styleTag.innerHTML += '.receipt { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); margin: 0; }'; } else { const newStyle = document.createElement('style'); newStyle.innerHTML = '.receipt { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); margin: 0; }'; document.head.appendChild(newStyle); } `; // 保存原始HTML,以便在注入后可以恢復 const originalReceiptTableHTML = receiptTable.innerHTML; receiptTable.innerHTML += `<script>window.onload = () => { ${cssCenteringScript}; window.print(); }</script>`; const receiptSectionHTML = document.querySelector('.receipt-section').innerHTML; const dataUri = 'data:text/html,' + encodeURIComponent(receiptSectionHTML); window.open(dataUri, '_blank'); // 在新標簽頁中打開并觸發(fā)打印 // 打印完成后(或者立即),恢復原始HTML,移除注入的腳本 // 注意:由于是新窗口打開,這里立即恢復對當前頁面DOM沒有影響 receiptTable.innerHTML = originalReceiptTableHTML; }
將上述步驟整合,并添加一個按鈕來觸發(fā) printReceipt 函數(shù):
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>打印特定元素教程</title> <style> body { font-family: sans-serif; margin: 20px; } .printButton { padding: 10px 20px; font-size: 16px; cursor: pointer; margin-bottom: 20px; } /* 頁面其他內(nèi)容,確保它不會被打印 */ .other-content { background-color: #f0f0f0; padding: 20px; border: 1px solid #ccc; margin-top: 20px; } </style> </head> <body> <h1>網(wǎng)頁特定元素打印示例</h1> <button class="printButton">打印收據(jù)</button> <div class="other-content"> 這是頁面上的其他內(nèi)容,不應被打印。 <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p> </div> <section class="receipt-section"> <table class="receipt"> <style> /* 收據(jù)表格的專用樣式 */ .receipt { border-collapse: collapse; max-width: 80%; /* 原始頁面顯示時的最大寬度 */ font-family: sans-serif; width: 100%; /* 打印時通常希望寬度占滿 */ } .receipt td { padding: .5em; } .receipt tr:nth-child(even) { border: 1px solid #333; border-inline: none; background: #ddd; } .receipt tr:nth-child(odd) { background: #fff } .header-Uprice, .item-Uprice, .header-qty, .item-qty { text-align: center } .total { border-bottom: 3px double #000 } </style> <tr class="table-headers"> <td class="header-id">#</td> <td class="header-desc">Item Description</td> <td class="header-Uprice">Unit Price</td> <td class="header-qty">Qty</td> <td class="header-price">Price</td> </tr> <tr class="item" id="1"> <td class="item-id">1</td> <td class="item-desc">Dummy Item1</td> <td class="item-Uprice">200$</td> <td class="item-qty">1</td> <td class="item-price">200$</td> </tr> <tr class="item" id="2"> <td class="item-id">2</td> <td class="item-desc">Dummy Item2</td> <td class="item-Uprice">75$</td> <td class="item-qty">1</td> <td class="item-price">75$</td> </tr> <tr class="item" id="3"> <td class="item-id">3</td> <td class="item-desc">Dummy Item3</td> <td class="item-Uprice">100$</td> <td class="item-qty">2</td> <td class="item-price">200$</td> </tr> <tr class="total"> <td>Total</td> <td></td> <td></td> <td></td> <td>475$</td> </tr> </table> </section> <script> function printReceipt() { const receiptTable = document.querySelector('.receipt'); // 確保在獲取innerHTML之前,將可能需要居中的樣式注入到新頁面的head中 // 這里的cssCenteringScript會作為字符串被注入到新頁面的<script>中執(zhí)行 const cssCenteringScript = ` const styleTag = document.createElement('style'); styleTag.innerHTML = '.receipt { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); margin: 0; max-width: 80%; width: auto; }'; document.head.appendChild(styleTag); `; // 保存原始HTML,以便在注入后可以恢復 const originalReceiptTableHTML = receiptTable.innerHTML; // 注入自動打印的腳本到收據(jù)表格內(nèi)容中 // 這個腳本會在新打開的Data URI頁面中執(zhí)行 receiptTable.innerHTML += `<script>window.onload = () => { ${cssCenteringScript}; window.print(); };<\/script>`; const receiptSectionHTML = document.querySelector('.receipt-section').innerHTML; const dataUri = 'data:text/html,' + encodeURIComponent(receiptSectionHTML); window.open(dataUri, '_blank'); // 在新標簽頁中打開并觸發(fā)打印 // 恢復原始HTML,移除注入的腳本,避免影響當前頁面的DOM // 這一步在window.open之后立即執(zhí)行,不會影響新打開的Data URI頁面 receiptTable.innerHTML = originalReceiptTableHTML; } const button = document.querySelector('.printButton'); button.addEventListener('click', printReceipt); </script> </body> </html>
瀏覽器兼容性:window.open() 和 data: URI 在現(xiàn)代瀏覽器中普遍支持,但某些瀏覽器可能會有對Data URI長度的限制。對于非常大的HTML內(nèi)容,這種方法可能不適用。
安全性:使用 window.open() 打開 data: URI 通常被認為是安全的,因為內(nèi)容是本地生成的。然而,如果Data URI的內(nèi)容來自不可信的第三方,則可能存在跨站腳本(XSS)風險。在本例中,內(nèi)容來自當前頁面DOM,因此風險較低。
打印樣式控制 (@media print):對于更專業(yè)的打印布局,推薦使用CSS的 @media print 媒體查詢。通過定義專門的打印樣式表,可以精確控制打印時的頁面布局、字體大小、隱藏非打印元素等,而無需JavaScript的動態(tài)注入。例如:
/* style.css */ /* 默認屏幕樣式 */ .receipt-section { display: block; } .print-button { display: block; } @media print { /* 打印時隱藏所有非收據(jù)內(nèi)容 */ body > *:not(.receipt-section) { display: none; } /* 讓收據(jù)居中 */ .receipt-section { width: 100%; margin: auto; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } /* 確保收據(jù)表格寬度占滿 */ .receipt { width: 100%; max-width: none; /* 移除屏幕樣式中的最大寬度限制 */ } }
然后,JavaScript只需調(diào)用 window.print() 即可,無需構建Data URI和注入腳本。這種方法通常更健壯和易于維護。本教程介紹的方法是應對特定場景(如需要完全隔離打印內(nèi)容)的一種靈活變通方案。
用戶體驗:window.open() 可能會被瀏覽器的彈窗攔截器阻止,尤其是在用戶沒有明確交互(如點擊按鈕)的情況下。確保用戶行為觸發(fā)此函數(shù)可以避免此問題。
通過將特定HTML內(nèi)容封裝為Data URI,并巧妙地利用內(nèi)聯(lián)JavaScript在新頁面加載時觸發(fā) window.print(),我們可以實現(xiàn)一種高效且用戶友好的局部內(nèi)容打印解決方案。雖然這種方法在某些方面可能略顯“非傳統(tǒng)”,但它提供了一種無需復雜DOM操作即可實現(xiàn)局部打印的有效途徑。在實際項目中,開發(fā)者應根據(jù)具體需求權衡其與更標準的 @media print 方案的優(yōu)劣,選擇最適合的實現(xiàn)方式。
以上就是利用JavaScript和Data URI實現(xiàn)網(wǎng)頁特定元素打印教程的詳細內(nèi)容,更多請關注php中文網(wǎng)其它相關文章!
Copyright 2014-2025 http://ipnx.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號