想請問一下,我今天想使用 jsPDF 搭配 html2canvas 去實現螢幕截圖,並下載下來
目前程式碼中有 divToPrint 跟 divToPrint2 兩個 element 是需要被下載的部分,不過我希望在畫面中 divToPrint 是在 divToPrint2 前面,到了下載時反過來
請問如何同時下載這兩個 element(不在外層包一個 id),然後並讓他們下載順序顛倒?
const printDocument = () => {
const input = document.querySelector("#divToPrint");
html2canvas(input).then((canvas) => {
const input2 = document.querySelector("#divToPrint2");
html2canvas(input2).then((canvass) => {
const imgData = canvass.toDataURL("image/png");
const imgData2 = canvass.toDataURL("image/png");
const pdf = new jsPDF();
pdf.addImage(imgData2, "JPEG", 0, 0);
pdf.addImage(imgData, "JPEG", 0, 0);
pdf.save("download.pdf");
})
});
};
return (
<div className="App">
<div>
<div className="mb5">
<button onClick={printDocument}>Print</button>
</div>
<div id="divToPrint" className="mt4">
<div>Note: Here the dimensions of div are same as A4</div>
<div>You Can add any component here</div>
</div>
<div id="divToPrint2" className="mt4">
<div>Note: Here the dimensions of div are same as A4444</div>
<div>You Can add any component hereeee</div>
</div>
</div>
</div>
有兩個問題:
const imgData = canvass.toDataURL("image/png");
pdf.addImage(imgData2, "JPEG", 0, 0);
pdf.addImage(imgData2, "JPEG", 0, 0);
pdf.addImage(imgData, "JPEG", 0, 0);
應該分開一段距離:
pdf.addImage(imgData2, "JPEG", 0, 0);
pdf.addImage(imgData, "JPEG", 0, 100);
問題是, 這個距離可能會因為瀏覽器和解析度不同而產生間隔與誤差. 當然,您也可以計算imgData2的高度來自動調整, 只是要先等imgData2完成才可以計算. 另外, 在您的程式碼中, 您用了兩個promises套在一起, then+then. 建議用async/await分開來同步處理.
const printDocument = async () => {
try {
const input1 = document.querySelector("#divToPrint");
const input2 = document.querySelector("#divToPrint2");
const canvas2 = await html2canvas(input2);
const imgData2 = canvas2.toDataURL("image/png");
const canvas1 = await html2canvas(input1);
const imgData1 = canvas1.toDataURL("image/png");
//先產生img2
const img2 = new Image();
img2.src = imgData2;
//等候img2完成後才計算
img2.onload = () => {
// 計算高度
const img2Height = img2.height;
// 產生pdf
const pdf = new jsPDF();
pdf.addImage(imgData2, "PNG", 0, 0);
pdf.addImage(imgData1, "PNG", 0, img2Height);
pdf.save("download.pdf");
};
} catch (error) {
console.error("Error generating PDF: ", error);
}
};
原來是分開兩個PDF:
const downloadAsPDF = async (selector, fileName) => {
try {
const element = document.querySelector(selector);
const canvas = await html2canvas(element);
const imgData = canvas.toDataURL("image/png");
const pdf = new jsPDF();
pdf.addImage(imgData, "PNG", 0, 0);
pdf.save(fileName);
} catch (error) {
console.error("Error generating PDF: ", error);
}
};
const printDocument = async (ms=2000) => {
await downloadAsPDF("#divToPrint2", "download2.pdf");
await new Promise(r => setTimeout(r, ms));
await downloadAsPDF("#divToPrint", "download1.pdf");
};
加入一個等候的時間, 預設2000ms, 以減少瀏覽器處理連續下載可能的問題:
await new Promise(r => setTimeout(r, ms));
要分成兩個檔案下載的話
下面是一個做法
但不同瀏覽器對於單一點擊事件觸發多次下載可能有不同的處理方式
不保證所有瀏覽器都一樣,這部分再看怎麼處理了
/**
* @param {string} selector CSS 選擇器的字串
* @param {string} filename 預設輸出檔名
*/
const downloadPdf = async (selector, filename) => {
const element = document.querySelector(selector);
const canvas = await html2canvas(element);
const pdf = new jsPDF();
pdf.addImage(canvas, "JPEG", 0, 0);
pdf.save(filename);
}
const printDocument = async () => {
await downloadPdf("#divToPrint2", "02.pdf");
await downloadPdf("#divToPrint", "01.pdf");
};