JavaScript圖片打印方案實例詳解
最近有個頁面打印圖片的小需求。就是系統(tǒng)界面展示有一些證件照片,我們希望可以點擊圖片旁邊的打印小按鈕,就可以將這張圖片直接打印到A4紙張上,例如下圖效果:

其實瀏覽器 window 對象提供了 print 方法,就可以對整個頁面進行打印。只需要點擊按鈕執(zhí)行以下方法即可。
window.print()
調用此方法,會打印出整個 html 里的內容,即 document 對象下所有的頁面節(jié)點。而我們需要的是只打印頁面的某個元素部分,即只打印圖片。
很遺憾,瀏覽器在 具體的dom 節(jié)點上并沒有部署 print 方法,不過我們可以轉變個思路,我們可以將需要打印的元素提取出來,同時構造一個新的window對象,將提取出來的元素插入到這個window對象下,再調用打印即可。
<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 對象,再調用 document.write 寫入我們獲取到指定節(jié)點,再打印即可。
這種方式有點不好的就是需要重新開一個 window ,并且設置一些打印的樣式會比較麻煩。所以不推薦。
我查閱了一些知名的打印插件,都是采用的 iframe 來構造頁面來實現(xiàn)局部打印的。iframe 有個屬性 srcdoc可以渲染指定的html內容
<iframe srcdoc="<p>Hello world!</p>"></iframe>
以往我們都是通過src來加載一個指定的頁面地址,這里通過 srcdoc 來渲染指定的html內容。下面實現(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)了,可是為了讓打印體驗更好,產品經理又提出了需求點:
當圖片是橫圖時,即寬度大于高度的圖片時,需要將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);居中問題解決了,接下來就是解決圖片盡可能鋪滿紙張問題。這個時候我們需要結合容器大小以及圖片寬高比來手動計算圖片寬高,算法如下:
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);
});
}總結
到此這篇關于JavaScript圖片打印方案的文章就介紹到這了,更多相關JavaScript 圖片打印內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
ES6中export?default和export之間的區(qū)別詳解
export和export?default都是es6語法中用來導出組件的,可以導出的文檔類型有(?數據、常量、函數、js文件、模塊等),下面這篇文章主要給大家介紹了關于ES6中export?default和export之間的區(qū)別的相關資料,需要的朋友可以參考下2023-04-04
AngularJs+Bootstrap實現(xiàn)漂亮的計算器
這篇文章主要為大家詳細介紹了angularJs+Bootstrap實現(xiàn)漂亮的計算器,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08

