所見即所得 —— HTML轉圖片元件開發
這是第 160 篇不摻水的原創,想獲取更多原創好文,請搜尋公眾號【政採雲前端團隊】關注我們吧~
前言
在我們日常開發中一定會遇到"所見即所得"
的需求,如匯出查詢表格中的內容為Excel表格——《前端匯出Excel,讓後端刮目相看》、通過後臺網頁配置實現配置預覽頁與實際頁面展示的統一——《從零開發一款視覺化大屏製作平臺》。
今天我們也來實現一個"所見即所得"的需求:將使用者所見網頁提取為圖片。
方案1:最短步驟實現結果
第一個想到的方案就是通過瀏覽器自帶的網頁另存為圖片去實現。
但這種方法顯然是不可行的。第一需要提示使用者操作進行繁瑣的操作,第二無法達到區域性提取為圖片的效果。
方案2:達成初步可行方案
通過調研發現,可以使用 html2canvas 將網頁先轉換為 canvas
資料。再將其轉換為圖片的方法,最終實現我們想要的功能。
引入html2canvas
cnpm install --save html2canvas
HTML ```html
名稱:
年齡:
班級:
```
JS
js
// 點選儲存為Canvas
onSaveCanvas(){
// 這裡的類名要與點選事件裡的一樣
const canvas = document.querySelector('#screenshot-box');
let that = this;
html2canvas(canvas,{scale:2,logging:false,useCORS:true}).then(function(canvas) {
const type = 'png';
let imgData = canvas.toDataURL(type);
// 圖片格式處理
let _fixType = function(type) {
type = type.toLowerCase().replace(/jpg/i, 'jpeg');
let r = type.match(/png|jpeg|bmp|gif/)[0];
return 'image/' + r;
};
imgData = imgData.replace(_fixType(type),'image/octet-stream');
let filename = "htmlImg" + '.' + type;
// 儲存為檔案
// 以bolb檔案下載
that.downFileToLocal(filename,that.convertBase64ToBlob(imgData))
});
},
如此我們便實現了初步的功能。
當然,我們也可以設定一個預覽圖片來預覽我們將要匯出的圖片。
HTML
html
<img :src="previewPic" alt="預覽圖片">
JS
js
this.previewPic = URL.createObjectURL(that.convertBase64ToBlob(imgData));
展示效果
將方案進行拓展並升級
需求止步於此,但秉承著"將事情做的更好"的我們豈能止步於此。
實現HTML匯出為Word
我們需要通過 html-docx 來實現匯出為Word(匯出Word目前只支援原生HTML + CSS)。
引入html-docx
cnpm install --save html-docx-js
HTML
```html
姓名 | 年齡 |
---|---|
賈維斯 | 2 |
<a-button @click="onWordExport">匯出為word</a-button>
JS
js
onWordExport(){
var contentHtml = document.getElementById("export-word").innerHTML;
const cssHTML = table {
width: 200px;
border: 1px solid #ccc;
color:red;
}
var content = <!DOCTYPE html><html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style>
${cssHTML}
</style>
</head>
<body>
${contentHtml}
</body>
</html>
var converted = htmlDocx.asBlob(content,{orientation:"landscape"});
this.downFileToLocal('word檔名.docx',converted)
}
```
展示效果
如此我們便實現了匯出 HTML 為 Word。
實現HTML匯出為PDF
目前市面上 HTML 匯出 PDF 的實現方式有多種,如jsPDF、iText、wkhtmltopdf等。在不同情況下我們應該使用不同的解決方案:
| 方案 | 優點 | 缺點 | 分頁 | 圖片 | 表格 | 連結 | 中文 | 特殊字元 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | jsPDF | 1、整個過程在客戶端執行(不需要伺服器參與),呼叫簡單 | 1、生成的pdf為圖片形式,且內容失真 | 支援 | 支援 | 支援 | 不支援 | 支援 | 支援 | | iText | 1、功能基本可以實現,比較靈活 2、生成pdf質量較高 | 1、對html標籤嚴格,少一個結束標籤就會報錯;2、後端實現複雜,伺服器需要安裝字型;3、圖片渲染比較複雜 | 支援 | 支援 | 支援 | 支援 | 支援 | 支援 | | wkhtmltopdf | 1、呼叫方式簡單;2、生成pdf質量較高 | 1、伺服器需要安裝wkhtmltopdf環境;2、根據網址生成pdf,對於有許可權控制的頁面需要在攔截器進行處理 | 支援 | 支援 | 支援 | 支援 | 支援 | 支援 |
今天我們使用在客戶端執行(不需要伺服器參與)的方式——jsPDF。
匯入jsPDF
npm install --save jspdf
HTML
html
<a-button @click="onPDFExport">匯出為PDF</a-button>
JS
```js
// 匯出為PDF
onPDFExport(){
const canvas = document.querySelector('#screenshot-box');
html2canvas(canvas).then(function(canvas) {
let contentWidth = canvas.width;
let contentHeight = canvas.height;
//一頁pdf顯示html頁面生成的canvas高度;
let pageHeight = contentWidth / 592.28 * 841.89;
//未生成pdf的html頁面高度
let leftHeight = contentHeight;
//頁面偏移
let position = 0;
//a4紙的尺寸[595.28,841.89],html頁面生成的canvas在pdf中圖片的寬高
let imgWidth = 595.28;
let imgHeight = 592.28/contentWidth * contentHeight;
let pageData = canvas.toDataURL('image/jpeg', 1.0);
let pdf = new jsPDF('', 'pt', 'a4');
//有兩個高度需要區分,一個是html頁面的實際高度,和生成pdf的頁面高度(841.89)
//當內容未超過pdf一頁顯示的範圍,無需分頁
if (leftHeight < pageHeight) {
pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight );
} else {
while(leftHeight > 0) {
pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
leftHeight -= pageHeight;
position -= 841.89;
//避免新增空白頁
if(leftHeight > 0) {
pdf.addPage();
}
}
}
pdf.save('content.pdf');
})
}
```
展示效果
如此我們便實現了匯出 HTML 為 PDF。
將功能封裝為元件
實現一次HTML匯出圖片需要寫的程式碼太多,很多引數也需要按需定製。是否能夠將其封裝成元件呢?
我們可以通過Vue的插槽將我們匯出的內容進行插入
完整元件
```HTML
```
Attributes
| 引數 | 型別 | 說明 | | --- | --- | --- | |id |String |唯一ID,盒子內容將作為匯出內容 | |filename |String |匯出的檔名稱(不帶檔案型別字尾) | |outType | String | 匯出檔案型別 | |isFile| Boolean |是否匯出為檔案,true將下載檔案,false返回bolb路徑 |
Methods
| 方法 | 名稱 | 說明 | | --- | --- | --- | | onSaveCanvas | 執行匯出或儲存方法 | 若isFile為true則儲存檔案,若isFile為false則返回bolb路徑 |
Events
| 方法 | 名稱 | 說明 | | --- | --- | --- | | onExport | 匯出方法 | 當觸發匯出/下載時會觸發該方法輸出 Bolb路徑 型別String |
使用元件
HTML
html
<Html2Image ref="html2Image" @onExport="exportPic" >
<div class="export-content" style="border: 1px solid #F0F;width:200px">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
</Html2Image>
<a-button @click="onExportImgByComponent">元件匯出為圖片</a-button>
JS
```js
// 引入元件
import Html2Image from '@/components/Html2Image/Html2Image.vue'
// 使用元件
components: {
Html2Image
},
// methods
onExportImgByComponent(){
this.previewPicComponent =this.$refs.html2Image.onSaveCanvas()
},
exportPic(baseUrl){
// 賦值匯出圖片的blob路徑
this.previewPicComponent = baseUrl;
},
```
Q&A
Q.為什麼外網圖片展示不出?
A: 設定 html2canvas 方法中 useCORS 為 true 即可。
最後要說的
專案地址: https://github.com/FireSmallPanda/vuexDemo.git
HTML匯出為圖片元件地址:HTML匯出為圖片元件
根據需求目前只封裝了HTML匯出為圖片,相信大家可以依葫蘆畫瓢將匯出Word和PDF也一併封裝為元件。
參考文章
《base64字串轉Blob檔案流,Blob檔案流再下載到本地》
推薦閱讀
開源作品
- 政採雲前端小報
開源地址 www.zoo.team/openweekly/ (小報官網首頁有微信交流群)
- 商品選擇 sku 外掛
開源地址 https://github.com/zcy-inc/skuPathFinder-back/
招賢納士
政採雲前端團隊(ZooTeam),一個年輕富有激情和創造力的前端團隊,隸屬於政採雲產品研發部,Base 在風景如畫的杭州。團隊現有 90 餘個前端小夥伴,平均年齡 27 歲,近 4 成是全棧工程師,妥妥的青年風暴團。成員構成既有來自於阿里、網易的“老”兵,也有浙大、中科大、杭電等校的應屆新人。團隊在日常的業務對接之外,還在物料體系、工程平臺、搭建平臺、效能體驗、雲端應用、資料分析及視覺化等方向進行技術探索和實戰,推動並落地了一系列的內部技術產品,持續探索前端技術體系的新邊界。
如果你想改變一直被事折騰,希望開始能折騰事;如果你想改變一直被告誡需要多些想法,卻無從破局;如果你想改變你有能力去做成那個結果,卻不需要你;如果你想改變你想做成的事需要一個團隊去支撐,但沒你帶人的位置;如果你想改變既定的節奏,將會是“5 年工作時間 3 年工作經驗”;如果你想改變本來悟性不錯,但總是有那一層窗戶紙的模糊… 如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望參與到隨著業務騰飛的過程,親手推動一個有著深入的業務理解、完善的技術體系、技術創造價值、影響力外溢的前端團隊的成長曆程,我覺得我們該聊聊。任何時間,等著你寫點什麼,發給 [email protected]
- 內網穿透你真的瞭解嗎?
- 前端本地化部署
- 所見即所得 —— HTML轉圖片元件開發
- 表單資料形式配置化設計
- 如何將傳統 Web 框架部署到 Serverless
- 淺談前端埋點 & 監控
- 如何讓 x == 1 && x == 2 && x == 3 等式成立
- 資料統計在效能檢測中的應用
- Web Components-LitElement實踐
- 模組聯邦淺析
- 效能優化——圖片壓縮、載入和格式選擇
- 如何基於 WebComponents 封裝 UI 元件庫
- Web Worker
- CDP 遠端除錯方案
- 一名練習時長 2 年零 8 個月的前端練習生自述
- 我在工作中是如何使用 git 的
- 如何利用 SCSS 實現一鍵換膚
- 淺析 FormData
- 前端工程師生產環境 debugger 技巧
- 在政採雲如何寫前端技術方案文件