純JS前端實(shí)現(xiàn)PDF從生成到下載的全過(guò)程
前因
接了個(gè)純前端開(kāi)發(fā)需求:做一個(gè)表單填寫(xiě)網(wǎng)站,用戶填完信息后,直接根據(jù)表單內(nèi)容在線生成 PDF 并下載。
我:這還不簡(jiǎn)單?拿到所有數(shù)據(jù)畫(huà)出html直接html2pdf轉(zhuǎn)一下不就完了,接!
結(jié)果需求一細(xì)化直接傻眼:客戶只要一個(gè)下載按鈕,不想看到預(yù)覽頁(yè)面,再看pdf模版文件——帶圖片、帶表單和大段文本,整整70-80頁(yè)。
我:- -??!
沒(méi)辦法活兒都接了,硬著頭皮干唄,調(diào)研一下只有jspdf符合我現(xiàn)有需求,既然有圖片,session肯定不夠存了,上indexDB把。最終使用RuoYi-Vue3 + jspdf + jspdf-autotable + dexie。
廢話不多說(shuō),直接復(fù)盤 jsPDF 實(shí)戰(zhàn)中踩過(guò)的三大核心坑,全是干貨!:
1. 第一個(gè)就是字體
PDF強(qiáng)制要求使用思源黑體,但是給我的字體都是OTF格式,直接使用官方工具轉(zhuǎn)后無(wú)法讀取。
需要的自己打開(kāi) https://rawgit.com/MrRio/jsPDF/master/fontconverter/fontconverter.html
官方倉(cāng)庫(kù)也沒(méi)有現(xiàn)成的relugar和bold版本的TTF字體,翻找歷史Tag才找到可用字體。 更坑的是: 轉(zhuǎn)換后兩個(gè)字體80MB,加上網(wǎng)頁(yè)本身思源黑體,字體文件包破100MB了。 - -?。?!
后來(lái)找了一些字體精簡(jiǎn)包終于壓縮到20MB!
2. 文字換行的坑
一開(kāi)始都是使用jspdf使用splitTextToSize計(jì)算文字行數(shù),一開(kāi)始還好后期文本出現(xiàn)了很多英文和特殊符號(hào)后就遇到了問(wèn)題:換行變得莫名奇妙。反復(fù)檢查代碼都沒(méi)發(fā)現(xiàn)問(wèn)題,直到我打印了splitTextToSize渲染日志,才發(fā)現(xiàn)是他這個(gè)罪魁禍?zhǔn)?/strong>,查遍文檔也沒(méi)有找到解決方案。
怎么辦?只能自己干:
// 逐字遍歷
for (const char of para) {
const w = getCharWidth(char)
// 首行要扣掉縮進(jìn)寬度
let availableWidth
if (isFirstLine) {
// 首行:原寬度-縮進(jìn)
availableWidth = maxLineWidth - firstIndentWidth
} else {
// 非首行:有maxWidth就用maxWidth,沒(méi)有沿用maxLineWidth
availableWidth = secondWidth > 0 ? secondWidth : maxLineWidth
}
// 能放下 → 加字
if (currentWidth + w <= availableWidth) {
currentLine += char
currentWidth += w
}
// 放不下 → 換行
else {
if (currentLine) {
lines.push(currentLine)
}
currentLine = char
currentWidth = w
isFirstLine = false
}
}
3.圖片渲染
調(diào)用官方APIpdf.addImage,Base64圖片、canvas甚至網(wǎng)絡(luò)圖片我都試了,都可以拿到數(shù)據(jù),打印方法日志也是正常,但是PDF就是不顯示圖片,感覺(jué)就像PDF沒(méi)有渲染出來(lái)一樣也不是空白。我試盡了各種辦法始終無(wú)果。
直到同時(shí)提醒:會(huì)不會(huì)是一步問(wèn)題? 這才恍然大悟——所有情況都考慮了,唯獨(dú)忽略了圖片加載異步的問(wèn)題。
總結(jié)
以上是項(xiàng)目落地jsPDF碰到的全部問(wèn)題。大佬們或許早已司空見(jiàn)慣,文章僅做實(shí)戰(zhàn)復(fù)盤、技術(shù)交流,有更好的處理思路歡迎一起討論。
到此這篇關(guān)于純JS前端實(shí)現(xiàn)PDF從生成到下載的全過(guò)程的文章就介紹到這了,更多相關(guān)JS PDF生成到下載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js光標(biāo)定位文本框回車表單提交問(wèn)題的解決方法
這篇文章主要介紹了js光標(biāo)定位文本框回車表單提交問(wèn)題的解決方法,涉及javascript阻止瀏覽器默認(rèn)事件的方法,需要的朋友可以參考下2015-05-05
JavaScript創(chuàng)建一個(gè)object對(duì)象并操作對(duì)象屬性的用法
這篇文章主要介紹了JavaScript創(chuàng)建一個(gè)object對(duì)象并操作對(duì)象屬性的用法,實(shí)例分析了javascript使用object類定義對(duì)象及屬性的用法,需要的朋友可以參考下2015-03-03
javascript getElementByTagName的使用
javascript getElementByTagName當(dāng)鼠標(biāo)放上去時(shí)將超鏈接的顏色設(shè)為藍(lán)色的。2009-06-06
使用layui的router來(lái)進(jìn)行傳參的實(shí)現(xiàn)方法
今天小編就為大家分享一篇使用layui的router來(lái)進(jìn)行傳參的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-09-09
javascript中for/in循環(huán)及使用技巧
如果您希望一遍又一遍地運(yùn)行相同的代碼,并且每次的值都不同,那么使用循環(huán)是很方便的,本篇文章給大家介紹javascript中for/in循環(huán)及使用技巧 ,需要的朋友可以參考下2015-09-09
JavaScript深度復(fù)制(deep clone)的實(shí)現(xiàn)方法
本文給大家介紹JavaScript深度復(fù)制(deep clone)的實(shí)現(xiàn)方法,涉及到j(luò)s深度復(fù)制相關(guān)知識(shí),本文介紹的非常詳細(xì),特此分享腳本之家平臺(tái)供大家參考2016-02-02

