JavaScript圖片打印方案實例詳解
最近有個頁面打印圖片的小需求。就是系統(tǒng)界面展示有一些證件照片,我們希望可以點擊圖片旁邊的打印小按鈕,就可以將這張圖片直接打印到A4紙張上,例如下圖效果:
其實瀏覽器 window 對象提供了 print 方法,就可以對整個頁面進行打印。只需要點擊按鈕執(zhí)行以下方法即可。
window.print()
調(diào)用此方法,會打印出整個 html 里的內(nèi)容,即 document 對象下所有的頁面節(jié)點。而我們需要的是只打印頁面的某個元素部分,即只打印圖片。
很遺憾,瀏覽器在 具體的dom 節(jié)點上并沒有部署 print 方法,不過我們可以轉(zhuǎn)變個思路,我們可以將需要打印的元素提取出來,同時構(gòu)造一個新的window對象,將提取出來的元素插入到這個window對象下,再調(diào)用打印即可。
<button @click="print">打印</button> <div id="box"> <img src="/test.jpg"/> </div>
例如我們只需要打印id="box"下的 img
print(){ const el = document.querySelector("#box") var newWindow=window.open("打印窗口","_blank"); var docStr = el.innerHTML; newWindow.document.write(docStr); newWindow.document.close(); newWindow.print(); newWindow.close(); },
通過 window.open 方式返回一個新的 window 對象,再調(diào)用 document.write 寫入我們獲取到指定節(jié)點,再打印即可。
這種方式有點不好的就是需要重新開一個 window ,并且設置一些打印的樣式會比較麻煩。所以不推薦。
我查閱了一些知名的打印插件,都是采用的 iframe
來構(gòu)造頁面來實現(xiàn)局部打印的。iframe 有個屬性 srcdoc
可以渲染指定的html內(nèi)容
<iframe srcdoc="<p>Hello world!</p>"></iframe>
以往我們都是通過src來加載一個指定的頁面地址,這里通過 srcdoc 來渲染指定的html內(nèi)容。下面實現(xiàn)一個最簡單的點擊按鈕打印圖片功能:
// 打印 function btnClick(){ const iframe = document.createElement('iframe') // 視覺上隱藏 iframe iframe.style.height = 0 iframe.style.visibility = 'hidden' iframe.style.width = 0 const str = `<html> <style media='print'> @page{size:A4 landscape};margin:0mm;padding:0} </style> <body> <div id="box"></div> </body> </html> ` iframe.setAttribute('srcdoc', str); document.body.appendChild(iframe); // 一定要加載完成后執(zhí)行 iframe.addEventListener("load",()=>{ const image = document.querySelector('img').cloneNode(); image.style.display = 'block' const box = iframe.contentDocument.querySelector('#box'); box.appendChild(image); // 一定要圖片加載完再打印 image.addEventListener('load', function () { // 打印 iframe.contentWindow.print(); }); }) iframe.contentWindow.addEventListener('afterprint', function () { iframe.parentNode.removeChild(iframe); }); }
對于打印的樣式設置,可以通過在style標簽上添加media=print
來設置
<style media='print'> @page{size:A4 landscape};margin:0mm;padding:0} </style>
上述就指定了打印機默認格式為A4紙張 橫向打印 ,margin設置成0毫米是為了保證不出現(xiàn)頁眉頁腳。
基礎功能的打印實現(xiàn)了,可是為了讓打印體驗更好,產(chǎn)品經(jīng)理又提出了需求點:
當圖片是橫圖時,即寬度大于高度的圖片時,需要將A4紙張橫向打印,然后圖片在A4里面上下左右都居中。同時要將這張圖片盡可能地鋪滿A4紙張,也不能改變圖片的寬高比(即不變形)。
當圖片是縱圖時,即寬度小于高度的圖片時,需要將A4紙張縱向打印,然后圖片在A4里面上下左右都居中。同時要將這張圖片盡可能地鋪滿A4紙張,也不能改變圖片的寬高比(即不變形)。
圖片不要緊挨著紙張邊緣,留出一定邊距。
橫圖效果:
縱圖效果:
實現(xiàn)思路: 由于要保證紙張邊緣留有一定的空白區(qū)域,這個時也可以使用 margin 來實現(xiàn)。
<style media='print'> @page{size:A4 landscape;margin:10mm;} </style>
但是不將 margin 設置成 0 的話,又會默認出現(xiàn)頁眉頁腳。這顯然是矛盾的。這個時候我想到了一個好的思路,就是將圖片放置到一個 div 容器里,這個 div 寬高設置成 A4 一樣的大小。同時將div里面的圖片通過 flex 布局來實現(xiàn)上下左右都居中。然后打印區(qū)域設置成這個容器就可以了。
由于 div 和 A4 紙張一樣大,所以 @page 里可以設置成 margin:0mm 來規(guī)避頁眉頁腳的出現(xiàn)。然后里面的圖片需要居中
// 獲取圖片寬高比 const rate = owidth/oheight // 橫圖的話容器寬度就是A4的高度,即29.7cm,縱圖的話寬度就是21cm,由于剛好設置成21cm會溢出,多出一張紙,原因未明,所以我設置成20.9 const boxWidthCM = `${rate >1 ? 29.7 : 20.9}cm` // 容器高度 const boxHeightCM = `${rate >1 ? 20.9 : 29.7}cm` const str = `<html> <style media='print'> @page{size:A4 ${rate>1 ? 'landscape':'portrait'};margin:0mm;padding:0} </style> <style> *{padding:0;margin:0} body{height:100%} #box{ width:${boxWidthCM}; height:${boxHeightCM}; display:flex; align-items:center; justify-content:center; } </style> <body> <div id="box"></div> </body> </html>` iframe.setAttribute('srcdoc', str);
居中問題解決了,接下來就是解決圖片盡可能鋪滿紙張問題。這個時候我們需要結(jié)合容器大小以及圖片寬高比來手動計算圖片寬高,算法如下:
let imgW = null; let imgH = null; if(rate > 1){ // 橫圖 if(rate>1.414){ imgW = 29.7 imgH = 29.7/rate } else { imgH = 20.9 imgW = 20.9*rate } } else { if(rate>(1/1.414)){ imgW = 20.9 imgH = 20.9/rate } else { imgH = 29.7 imgW = 29.7*rate } } // 預留1cm邊距 imgW = imgW - 1 imgH = imgW/rate iframe.addEventListener("load",()=>{ const image = document.createElement("img") image.style.width = item.width image.style.height = item.height image.style.display = 'block' image.src = item.newUrl || item.url || item.original_content_url image.style.width = `${imgW}cm` image.style.height = `${imgH}cm` const box = iframe.contentDocument.querySelector('#box'); box.appendChild(image); image.addEventListener('load', function () { iframe.contentWindow.print(); }); })
完整代碼:
print(item){ const { owidth,oheight,height } = item const rate = owidth/oheight const imgHeight = height.replace("px","") const iframe = document.createElement('iframe') iframe.style.height = 0 iframe.style.visibility = 'hidden' iframe.style.width = 0 const boxWidthCM = `${rate >1 ? 29.7 : 20.9}cm` const boxHeightCM = `${rate >1 ? 20.9 : 29.7}cm` let imgW = null; let imgH = null; if(rate > 1){ // 橫圖 if(rate>1.414){ imgW = 29.7 imgH = 29.7/rate } else { imgH = 20.9 imgW = 20.9*rate } } else { if(rate>(1/1.414)){ imgW = 20.9 imgH = 20.9/rate } else { imgH = 29.7 imgW = 29.7*rate } } // 預留1cm邊距 imgW = imgW - 1 imgH = imgW/rate const str = `<html> <style media='print'> @page{size:A4 ${rate>1 ? 'landscape':'portrait'};margin:0mm;padding:0} </style> <style> *{padding:0;margin:0} body{height:100%} #box{ width:${boxWidthCM}; height:${boxHeightCM}; display:flex; align-items:center; justify-content:center; } </style> <body> <div id="box"></div> </body> </html>` iframe.setAttribute('srcdoc', str); document.body.appendChild(iframe); iframe.addEventListener("load",()=>{ const image = document.createElement("img") image.style.width = item.width image.style.height = item.height image.style.display = 'block' image.src = item.newUrl || item.url || item.original_content_url image.style.width = `${imgW}cm` image.style.height = `${imgH}cm` const box = iframe.contentDocument.querySelector('#box'); box.appendChild(image); image.addEventListener('load', function () { iframe.contentWindow.print(); }); }) iframe.contentWindow.addEventListener('afterprint', function () { iframe.parentNode.removeChild(iframe); }); }
總結(jié)
到此這篇關(guān)于JavaScript圖片打印方案的文章就介紹到這了,更多相關(guān)JavaScript 圖片打印內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
ES6中export?default和export之間的區(qū)別詳解
export和export?default都是es6語法中用來導出組件的,可以導出的文檔類型有(?數(shù)據(jù)、常量、函數(shù)、js文件、模塊等),下面這篇文章主要給大家介紹了關(guān)于ES6中export?default和export之間的區(qū)別的相關(guān)資料,需要的朋友可以參考下2023-04-04AngularJs+Bootstrap實現(xiàn)漂亮的計算器
這篇文章主要為大家詳細介紹了angularJs+Bootstrap實現(xiàn)漂亮的計算器,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08深入剖析JavaScript中的函數(shù)currying柯里化
下面小編就為大家?guī)硪黄钊肫饰鯦avaScript中的函數(shù)currying柯里化。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考,一起跟隨小編過來看看吧2016-04-04Gulp實現(xiàn)靜態(tài)網(wǎng)頁模塊化的方法詳解
眾所周知Gulp.js 是一個自動化構(gòu)建工具,開發(fā)者可以使用它在項目開發(fā)過程中自動執(zhí)行常見任務。下面這篇文章主要給大家介紹了關(guān)于Gulp實現(xiàn)靜態(tài)網(wǎng)頁模塊化的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下。2018-01-01