純js實現(xiàn)html轉(zhuǎn)pdf的簡單實例(推薦)
項目開發(fā)中遇到了一個變態(tài)需求,需要把一整個頁面導出為pdf格式,而且要保留頁面上的所有的表格、svg圖片和樣式。
簡而言之,就是希望像截圖一樣,把整個頁面截下來,然后保存成pdf。
咋不上天呢……
查了一下,能夠?qū)崿F(xiàn)html轉(zhuǎn)pdf的方法還是挺多的,大概有以下幾種:
1、大部分瀏覽器就有這個功能。然而我們客戶要的可不是這個,人家要的是能夠在系統(tǒng)中主動觸發(fā)的導出為pdf功能,所以這種方案pass。
2、利用第三方工具。我找到了一種利用wkhtmltopdf這種工具來導出的方案,自己在我們的項目中試了一下,效果不好,而且對svg圖片的支持也不行。pass。
3、還有一種是利用iText類后臺生成java文件。但因為需要導出的這個頁面是動態(tài)頁面,而且直接把頁面?zhèn)鹘o后臺會丟失大量樣式,所以還是pass。
最后沒什么好的辦法,只能退而求其次,想著要不先把html頁面轉(zhuǎn)成圖片,再把圖片導出為pdf。因為要支持用戶導出下載,而且要保留樣式,所以最好是純js前端實現(xiàn)。
html轉(zhuǎn)canvas的話,就用html2canvas這個js,這個網(wǎng)上介紹比較多了,這里就不廢話了。
比較麻煩的是svg圖片,直接用html2canvas無法把svg標簽的內(nèi)容轉(zhuǎn)成canvas,最后查了一圈資料后,鎖定了canvg這個js。canvg是谷歌的一個插件,可以將svg標簽內(nèi)容轉(zhuǎn)成canvas。具體到我們的項目,還有一個難點,就是如何把glyphicons這種字體圖標也轉(zhuǎn)成canvas,因為在不同瀏覽器下對這種字體圖標的支持是完全不一樣的。最后找到的方法是用char code來替換這些字體圖標,重新繪制成canvas。由canvas生成圖片不用廢話。由圖片生成pdf用jsPDF實現(xiàn)。 折騰了大半天,總算把整個流程打通了,接下來一步一步貼上代碼。
第一步:把對應dom節(jié)點里所有的svg元素替換成canvas
svg2canvas: function(targetElem) { var svgElem = targetElem.find('svg'); svgElem.each(function(index, node) { var parentNode = node.parentNode; //由于現(xiàn)在的IE不支持直接對svg標簽node取內(nèi)容,所以需要在當前標簽外面套一層div,通過外層div的innerHTML屬性來獲取 var tempNode = document.createElement('div'); tempNode.appendChild(node); var svg = tempNode.innerHTML; var canvas = document.createElement('canvas'); //轉(zhuǎn)換 canvg(canvas, svg); parentNode.appendChild(canvas); }); }
第二步:把glyphicons字體轉(zhuǎn)成canvas。如果項目中沒有用到glyphicons字體圖標,可忽略這一步
glyphicons2canvas: function(targetElem, fontClassName, fontFamilyName) { var iconElems = targetElem.find('.' + fontClassName); iconElems.each(function(index, inconNode) { var fontSize = $(inconNode).css("font-size"); var iconColor = $(inconNode).css("color"); var styleContent = $(inconNode).attr('style'); //去掉"px" fontSize = fontSize.replace("px", ""); var charCode = getCharCodeByGlyphiconsName(iconName); var myCanvas = document.createElement('canvas'); //把canva寬高各增加2是為了顯示圖標完整 myCanvas.width = parseInt(fontSize) + 2; myCanvas.height = parseInt(fontSize) + 2; myCanvas.style = styleContent; var ctx = myCanvas.getContext('2d'); //設置繪圖內(nèi)容的顏色 ctx.fillStyle = iconColor; //設置繪圖的字體大小以及font-family的名字 ctx.font = fontSize + 'px ' + fontFamilyName; ctx.fillText(String.fromCharCode(charCode), 1, parseInt(fontSize) + 1); $(inconNode).replaceWith(myCanvas); }); } //根據(jù)glyphicons/glyphicon圖標的類名獲取到對應的char code getCharCodeByGlyphiconsName: function(iconName) { switch (iconName) { case("glyphicons-resize-full"): return "0xE216"; case ("glyphicons-chevron-left"): return "0xE225"; default: return ""; } }
第三步:html轉(zhuǎn)canvas轉(zhuǎn)圖片再轉(zhuǎn)pdf
html2canvas($("#myExportArea"), { onrendered: function(canvas) { var imgData = canvas.toDataURL('image/jpeg'); var img = new Image(); img.src = imgData; //根據(jù)圖片的尺寸設置pdf的規(guī)格,要在圖片加載成功時執(zhí)行,之所以要*0.225是因為比例問題 img.onload = function() { //此處需要注意,pdf橫置和豎置兩個屬性,需要根據(jù)寬高的比例來調(diào)整,不然會出現(xiàn)顯示不完全的問題 if (this.width > this.height) { var doc = new jsPDF('l', 'mm', [this.width * 0.225, this.height * 0.225]); } else { var doc = new jsPDF('p', 'mm', [this.width * 0.225, this.height * 0.225]); } doc.addImage(imgData, 'jpeg', 0, 0, this.width * 0.225, this.height * 0.225); //根據(jù)下載保存成不同的文件名 doc.save('report_pdf_' + new Date().getTime() + '.pdf'); } }, background: "#fff", //這里給生成的圖片默認背景,不然的話,如果你的html根節(jié)點沒設置背景的話,會用黑色填充。 allowTaint: true //避免一些不識別的圖片干擾,默認為false,遇到不識別的圖片干擾則會停止處理html2canvas });
雖然最后勉強完成了客戶的要求,但是生成的pdf效果明顯不如正常截圖來的清晰……水平所限,暫時只能想到這種方法,如果大家有更好的辦法,歡迎指點。
以上這篇純js實現(xiàn)html轉(zhuǎn)pdf的簡單實例(推薦)就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Bootstrap carousel輪轉(zhuǎn)圖的使用實例詳解
圖片輪播效果在Web中常常能看到,很多人也稱之為幻燈片。這篇文章主要給大家介紹Bootstrap carousel輪轉(zhuǎn)圖的使用實例詳解,需要的朋友可以參考下2016-05-05JavaScript實現(xiàn)網(wǎng)頁版五子棋游戲
這篇文章主要為大家詳細介紹了JavaScript實現(xiàn)網(wǎng)頁版五子棋游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-07-07HTML5+setCutomValidity()函數(shù)驗證表單實例分享
本文給大家分享的是在HTML5中結合setCutomValidity()函數(shù)實現(xiàn)驗證表單的實例,非常的時間實用,這里推薦給大家,有需要的小伙伴可以參考下。2015-04-04javascript如何計算數(shù)組中某值的出現(xiàn)次數(shù)
這篇文章主要介紹了javascript如何計算數(shù)組中某值的出現(xiàn)次數(shù)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-01-01