瀏覽器列印的兩種實踐方案
1.瀏覽器自身列印
- 使用
window.print()
調起瀏覽器自帶的列印預覽彈框列印 - 預設會列印
body
裡面所有內容
js
const handlePrintPdf = () => {
window.print();
}
如果想要區域性列印可以使用 CSS
媒體查詢,甚至還可以自定義列印時的樣式,這些樣式只會在列印的時候生效
```html
```
可使用媒體查詢在列印的時候去除頁首頁尾,設定列印佈局等操作
```css @media print { @page { / 去除頁首 / / margin-top: 0; / / 去除頁尾 / / margin-bottom: 0; / / 去掉頁首和頁尾 / margin: 0; / 縱向 / size: portrait; / 橫向 A4 / size:A4 landscape; }
body {
margin: 1cm;
}
}
```
如果內容固定且具有分頁,瀏覽器自身分頁可能會和預想中情況不一樣,我們可以使用 CSS
進行強制分頁
css
@media print {
/* 在main元素前始終插入分頁符,強制使其分到下一頁 */
main {
page-break-before: always;
}
/* 在footer元素後始終插入分頁符 */
footer {
page-break-after: always;
}
}
列印部分割槽域的內容還可以這樣做
動態建立一個不可見的 iframe
, 將需要列印的 dom
節點插入 iframe
內,並呼叫 iframe
的 print
方法
js
printBtn.addEventListener("click", () => {
const printContentHtml = document.getElementById("print").innerHTML;
const iframe = document.createElement("iframe");
iframe.setAttribute(
"style",
"position:absolute;width:0px;height:0px;left:-500px;top:-500px;"
);
document.body.appendChild(iframe);
iframe.contentDocument.write(printContentHtml);
iframe.contentDocument.close();
iframe.contentWindow.print();
document.body.removeChild(iframe);
})
或者在新開啟的頁面列印
js
printBtn.addEventListener("click", () => {
const printContentHtml = document.getElementById("print").innerHTML;
const printPage = window.open();
printPage.document.write(printContentHtml);
printPage.document.close();
printPage.print();
printPage.close();
})
當然我們也可以這樣,先獲取需要列印的 dom
節點,替換當前 body
下的節點。完成列印後恢復 body
下的節點
```html
段落1
段落2
段落3
```
這樣的話列印的時候頁面原有元素會丟失,並且這時可能圖片也未載入完成,很多元素寬度也會有問題要調整,我們可以更進一步封裝方便修改,整體程式碼如下:
```html
段落1~
段落2~
段落3~
```
很可惜此類方案和很多第三方庫會有元素丟失和樣式錯亂的情況,不盡如人意
此時一個方案浮出水面
2.html2canvas和jspdf
- 簡單說就是將網頁通過
html2canvas
(dom-to-image
也可以) 轉換為圖片,再由jspdf
生成該圖片的pdf
- 此方案也會有一些問題,例如
iframe
巢狀(專案中富文字編輯器會用到)的內容會無法列印,無法複製pdf
上的文字等內容,而且清晰度可能會存在問題 - 圖片輸出
pdf
的時候根據寬高裁切,分頁的時候可能會有內容生生的被截斷,需要根據不同專案特殊處理(邏輯複雜)
先來說說這兩者基本使用
安裝:
shell
yarn add html2canvas jspdf
使用 html2canvas
對頁面截圖
js
// allowTaint 是否允許跨域載入圖片
// useCORS 是否使用CORS從伺服器載入圖片
// scale 渲染畫素比率,預設當前裝置畫素比
printBtn.addEventListener("click", () => {
html2Canvas(wrap, { allowTaint: true, useCORS: true, scale: 2 }).then(
(canvas) => {
document.body.appendChild(canvas);
// 轉換canvase為base64圖片,第二個引數1代表圖片質量(0-1)
canvas.toDataURL("image/jpeg", 1);
}
);
});
此方法無法列印 iframe
裡面的內容,於是我遍歷整個 iframe
的 dom
替換,此外我們還要書寫邏輯手動對圖片指定寬高進行截圖分頁,此部分可以將其封裝下方便複用,具體方案如下
```html
```
注意列印完之後最好在頂層元件封裝個 reload
方法關聯 v-if
通過 provide
提供下去,元件呼叫下重新渲染一遍(因為之前我們替換了頁面元素,不重新整理還原可能會有問題)
js
reload() {
this.isRouteAlive = false;
this.$nextTick(() => {
this.isRouteAlive = true;
});
},
最後這個截斷問題比較棘手,我們可以這樣解決
- 設定對應轉換後的 canvas 為白色背景
- 轉換圖片後獲取對應截斷處的圖片畫素
- 從截斷處一行行往上掃描畫素點顏色
- 碰到這一行是全白的,代表從這裡截斷,將這個高度往下的內容放到下一頁
具體程式碼如下!
```html
```