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

其實(shí)瀏覽器 window 對象提供了 print 方法,就可以對整個(gè)頁面進(jìn)行打印。只需要點(diǎn)擊按鈕執(zhí)行以下方法即可。
window.print()
調(diào)用此方法,會打印出整個(gè) html 里的內(nèi)容,即 document 對象下所有的頁面節(jié)點(diǎn)。而我們需要的是只打印頁面的某個(gè)元素部分,即只打印圖片。
很遺憾,瀏覽器在 具體的dom 節(jié)點(diǎn)上并沒有部署 print 方法,不過我們可以轉(zhuǎn)變個(gè)思路,我們可以將需要打印的元素提取出來,同時(shí)構(gòu)造一個(gè)新的window對象,將提取出來的元素插入到這個(gè)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 方式返回一個(gè)新的 window 對象,再調(diào)用 document.write 寫入我們獲取到指定節(jié)點(diǎn),再打印即可。
這種方式有點(diǎn)不好的就是需要重新開一個(gè) window ,并且設(shè)置一些打印的樣式會比較麻煩。所以不推薦。
我查閱了一些知名的打印插件,都是采用的 iframe 來構(gòu)造頁面來實(shí)現(xiàn)局部打印的。iframe 有個(gè)屬性 srcdoc可以渲染指定的html內(nèi)容
<iframe srcdoc="<p>Hello world!</p>"></iframe>
以往我們都是通過src來加載一個(gè)指定的頁面地址,這里通過 srcdoc 來渲染指定的html內(nèi)容。下面實(shí)現(xiàn)一個(gè)最簡單的點(diǎ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);
});
}對于打印的樣式設(shè)置,可以通過在style標(biāo)簽上添加media=print來設(shè)置
<style media='print'>
@page{size:A4 landscape};margin:0mm;padding:0}
</style>上述就指定了打印機(jī)默認(rèn)格式為A4紙張 橫向打印 ,margin設(shè)置成0毫米是為了保證不出現(xiàn)頁眉頁腳。
基礎(chǔ)功能的打印實(shí)現(xiàn)了,可是為了讓打印體驗(yàn)更好,產(chǎn)品經(jīng)理又提出了需求點(diǎn):
當(dāng)圖片是橫圖時(shí),即寬度大于高度的圖片時(shí),需要將A4紙張橫向打印,然后圖片在A4里面上下左右都居中。同時(shí)要將這張圖片盡可能地鋪滿A4紙張,也不能改變圖片的寬高比(即不變形)。
當(dāng)圖片是縱圖時(shí),即寬度小于高度的圖片時(shí),需要將A4紙張縱向打印,然后圖片在A4里面上下左右都居中。同時(shí)要將這張圖片盡可能地鋪滿A4紙張,也不能改變圖片的寬高比(即不變形)。
圖片不要緊挨著紙張邊緣,留出一定邊距。
橫圖效果:

縱圖效果:

實(shí)現(xiàn)思路: 由于要保證紙張邊緣留有一定的空白區(qū)域,這個(gè)時(shí)也可以使用 margin 來實(shí)現(xiàn)。
<style media='print'>
@page{size:A4 landscape;margin:10mm;}
</style>但是不將 margin 設(shè)置成 0 的話,又會默認(rèn)出現(xiàn)頁眉頁腳。這顯然是矛盾的。這個(gè)時(shí)候我想到了一個(gè)好的思路,就是將圖片放置到一個(gè) div 容器里,這個(gè) div 寬高設(shè)置成 A4 一樣的大小。同時(shí)將div里面的圖片通過 flex 布局來實(shí)現(xiàn)上下左右都居中。然后打印區(qū)域設(shè)置成這個(gè)容器就可以了。

由于 div 和 A4 紙張一樣大,所以 @page 里可以設(shè)置成 margin:0mm 來規(guī)避頁眉頁腳的出現(xiàn)。然后里面的圖片需要居中
// 獲取圖片寬高比
const rate = owidth/oheight
// 橫圖的話容器寬度就是A4的高度,即29.7cm,縱圖的話寬度就是21cm,由于剛好設(shè)置成21cm會溢出,多出一張紙,原因未明,所以我設(shè)置成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);居中問題解決了,接下來就是解決圖片盡可能鋪滿紙張問題。這個(gè)時(shí)候我們需要結(jié)合容器大小以及圖片寬高比來手動(dòng)計(jì)算圖片寬高,算法如下:
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
}
}
// 預(yù)留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
}
}
// 預(yù)留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語法中用來導(dǎo)出組件的,可以導(dǎo)出的文檔類型有(?數(shù)據(jù)、常量、函數(shù)、js文件、模塊等),下面這篇文章主要給大家介紹了關(guān)于ES6中export?default和export之間的區(qū)別的相關(guān)資料,需要的朋友可以參考下2023-04-04
Bootstrap 附加導(dǎo)航(Affix)插件實(shí)例詳解
附加導(dǎo)航(Affix)插件允許某個(gè) <div> 固定在頁面的某個(gè)位置。接下來通過本文給大家介紹Bootstrap 附加導(dǎo)航(Affix)插件實(shí)例詳解,感興趣的朋友一起看看吧2016-06-06
AngularJs+Bootstrap實(shí)現(xiàn)漂亮的計(jì)算器
這篇文章主要為大家詳細(xì)介紹了angularJs+Bootstrap實(shí)現(xiàn)漂亮的計(jì)算器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
Bootstrap導(dǎo)航簡單實(shí)現(xiàn)代碼
這篇文章主要介紹了Bootstrap導(dǎo)航的簡單實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
深入剖析JavaScript中的函數(shù)currying柯里化
下面小編就為大家?guī)硪黄钊肫饰鯦avaScript中的函數(shù)currying柯里化。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考,一起跟隨小編過來看看吧2016-04-04
Gulp實(shí)現(xiàn)靜態(tài)網(wǎng)頁模塊化的方法詳解
眾所周知Gulp.js 是一個(gè)自動(dòng)化構(gòu)建工具,開發(fā)者可以使用它在項(xiàng)目開發(fā)過程中自動(dòng)執(zhí)行常見任務(wù)。下面這篇文章主要給大家介紹了關(guān)于Gulp實(shí)現(xiàn)靜態(tài)網(wǎng)頁模塊化的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下。2018-01-01
腳本吧 - 幻宇工作室用到j(luò)s,超強(qiáng)推薦base.js
腳本吧 - 幻宇工作室用到j(luò)s,超強(qiáng)推薦base.js...2006-12-12

