所見即所得 —— 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 即可。
最後要説的
項目地址: http://github.com/FireSmallPanda/vuexDemo.git
HTML導出為圖片組件地址:HTML導出為圖片組件
根據需求目前只封裝了HTML導出為圖片,相信大家可以依葫蘆畫瓢將導出Word和PDF也一併封裝為組件。
參考文章
《base64字串轉Blob文件流,Blob文件流再下載到本地》
推薦閲讀
開源作品
- 政採雲前端小報
開源地址 www.zoo.team/openweekly/ (小報官網首頁有微信交流羣)
- 商品選擇 sku 插件
開源地址 http://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 技巧
- 在政採雲如何寫前端技術方案文檔