我在一个小组报告系统中有一个解决方案,我在视图中呈现了选定数量的数据表,并且我提供了每个表的下载链接,即:
let singlePDFdownload = function (table_id) {
$(`.toolbar${table_id} .custom-pdf`).trigger('click')
}
这适用于单个下载,但我还想启用一个快速按钮,以便一次生成所有下载。我目前使用
.custom_pdf
类执行此操作,因此我可以对执行所述表的数据表导出的按钮进行分组。这是我目前使用的方式的一个问题,因为它会在浏览器中启动多次下载并弹出多个窗口(偶尔会显示警告)。
如何将这些“点击”合并为一次下载?
我能否捕获由于
trigger('click;)
而发生的下载,然后以某种方式将 PDF 合并到一个压缩文件夹中,或者如何实现?
这里是触发多次下载的代码:
const $massPDFExport = $('#massPDFExport')
$massPDFExport.on('click', () => {
// remember all tables shown have this class
$(`.custom-pdf`).trigger('click')
})
这是一个完全可重现的例子:
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/buttons/2.3.6/css/buttons.dataTables.min.css">
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/dataTables.buttons.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/pdfmake.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/vfs_fonts.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.html5.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.print.min.js"></script>
<script>
$(document).ready(function () {
$('#example_1').DataTable({
dom: 'Bfrtip',
buttons: [
'copy', 'csv', 'excel', 'pdf', 'print'
]
});
$('#example_2').DataTable({
dom: 'Bfrtip',
buttons: [
'copy', 'csv', 'excel', 'pdf', 'print'
]
});
$('#export_all').on('click', () => {
$('.buttons-pdf').each(function (a) {
console.log(9888)
$(this).trigger("click");
});
});
});
</script>
<a id='export_all' class=''> Export All As PDF</a>
<table id="example_1" class="display nowrap" style="width:100%">
<thead>
<tr>
<th>Name</th>
<th>Position</th>
<th>Office</th>
<th>Age</th>
<th>Start date</th>
<th>Salary</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tiger Nixon</td>
<td>System Architect</td>
<td>Edinburgh</td>
<td>61</td>
<td>2011-04-25</td>
<td>$320,800</td>
</tr>
<tr>
<td>Garrett Winters</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>63</td>
<td>2011-07-25</td>
<td>$170,750</td>
</tr>
</tbody>
</table>
<table id="example_2" class="display nowrap" style="width:100%">
<thead>
<tr>
<th>Name</th>
<th>Position</th>
<th>Office</th>
<th>Age</th>
<th>Start date</th>
<th>Salary</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tiger Nixon</td>
<td>System Architect</td>
<td>Edinburgh</td>
<td>61</td>
<td>2011-04-25</td>
<td>$320,800</td>
</tr>
<tr>
<td>Garrett Winters</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>63</td>
<td>2011-07-25</td>
<td>$170,750</td>
</tr>
</tbody>
</table>
我想出了一个解决方案,并想我会发布一个答案,展示一个简单的例子,说明如何使用数据表、JSZip 和 PDfMake 组合和压缩多个 PDF 文件,因为我找不到很多真实的例子。
总的来说,它归结为按钮定义的
customize
选项。
buttons.pdf.js
function customPdfButtonAction (e, dt, button, config) {
this.processing(true);
var that = this;
var data = dt.buttons.exportData(config.exportOptions);
var info = dt.buttons.exportInfo(config);
var rows = [];
if (config.header) {
rows.push(
$.map(data.header, function (d) {
return {
text: typeof d === "string" ? d : d + "",
style: "tableHeader"
};
})
);
}
for (var i = 0, ien = data.body.length; i < ien; i++) {
rows.push(
$.map(data.body[i], function (d) {
if (d === null || d === undefined) {
d = "";
}
return {
text: typeof d === "string" ? d : d + "",
style: i % 2 ? "tableBodyEven" : "tableBodyOdd"
};
})
);
}
if (config.footer && data.footer) {
rows.push(
$.map(data.footer, function (d) {
return {
text: typeof d === "string" ? d : d + "",
style: "tableFooter"
};
})
);
}
var doc = {
pageSize: config.pageSize,
pageOrientation: config.orientation,
content: [
{
table: {
headerRows: 1,
body: rows
},
layout: "noBorders"
}
],
styles: {
tableHeader: {
bold: true,
fontSize: 11,
color: "white",
fillColor: "#2d4154",
alignment: "center"
},
tableBodyEven: {},
tableBodyOdd: {
fillColor: "#f3f3f3"
},
tableFooter: {
bold: true,
fontSize: 11,
color: "white",
fillColor: "#2d4154"
},
title: {
alignment: "center",
fontSize: 15
},
message: {}
},
defaultStyle: {
fontSize: 10
}
};
if (info.messageTop) {
doc.content.unshift({
text: info.messageTop,
style: "message",
margin: [0, 0, 0, 12]
});
}
if (info.messageBottom) {
doc.content.push({
text: info.messageBottom,
style: "message",
margin: [0, 0, 0, 12]
});
}
if (info.title) {
doc.content.unshift({
text: info.title,
style: "title",
margin: [0, 0, 0, 12]
});
}
if (config.customize) {
config.customize(doc, config, dt);
}
var pdf = window.pdfMake.createPdf(doc);
if (config.download === "open" && !_isDuffSafari()) {
pdf.open();
} else {
// In case of silent mode — exit without downloading
if (e.detail.silent) return this.processing(false);
pdf.download(info.filename);
}
this.processing(false);
}
window.customPdfButtonAction = customPdfButtonAction
main_functionality.js
(function ($) {
let PDF_BLOB_PROMISES = [];
const buttons = [
"copy",
"csv",
"excel",
"print",
{
extend: "pdf",
text: "PDF",
customize: customPDFButtonCustomize, // here is the key
action: customPdfButtonAction // here is the key
}
]
// Push Blob to array of Promises
async function customPDFButtonCustomize(doc) {
try {
PDF_BLOB_PROMISES.push(
new Promise((resolve, reject) => {
window.pdfMake.createPdf(doc).getBlob(resolve);
})
);
} catch (e) {
console.error("Push PDF to Blob failed", e);
}
}
// Init Data tables
function initDT() {
$('[data-type="dt"]').each(function (i) {
const table = $(this).DataTable({
buttons
});
table
.buttons()
.container()
.appendTo(`#DataTables_Table_${i}_wrapper .col-md-6:eq(0)`);
});
}
// Export All button handler
async function exportAllPDF() {
try {
const zip = new window.JSZip();
const folder = zip.folder("pdf");
PDF_BLOB_PROMISES = [];
$(".buttons-pdf").each(function (a) {
const event = new CustomEvent("click", {
detail: {
silent: true
}
});
this.dispatchEvent(event);
});
const blobs = await Promise.all(PDF_BLOB_PROMISES);
if (!blobs.length) return;
for (let i = 0; i < blobs.length; i++) {
folder.file(`pdf-${i + 1}.pdf`, blobs[i]);
}
const zipped = await zip.generateAsync({ type: "blob" });
window.saveAs(zipped, "pdfs.zip");
} catch (e) {
console.error("Eport All PDF failed", e);
}
}
$(document).ready(function () {
// Init Data Tables
initDT();
// Export All button event listener
$("#export_all").on("click", exportAllPDF);
})
})(window.jQuery)
HTML 页面
<!DOCTYPE html>
<html>
<head>
<title>Show Me Some Magic</title>
<meta charset="UTF-8" />
<!-- CSS -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.2/css/bootstrap.css"
/>
<link
rel="stylesheet"
href="https://cdn.datatables.net/1.13.4/css/dataTables.bootstrap4.min.css"
/>
<link
rel="stylesheet"
href="https://cdn.datatables.net/buttons/2.3.6/css/buttons.bootstrap4.min.css"
/>
<style>
body {
padding: 2rem;
}
.dataTables_wrapper {
margin-bottom: 3rem;
}
.btn-export-all {
background: #afddff;
border-radius: 10px;
border: none;
padding: 10px 20px;
cursor: pointer;
}
</style>
<!-- VENDOR JS -->
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.13.4/js/dataTables.bootstrap4.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/dataTables.buttons.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.bootstrap4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/pdfmake.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/vfs_fonts.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.html5.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.print.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.colVis.min.js"></script>
<!-- Local JS -->
<script src="./js/buttons.pdf.js"></script>
<script src="./js/main_functionality.js"></script>
</head>
<body>
<div style="padding: 20px 0;">
<button id="export_all" class="btn-export-all">Export All As PDF</button>
</div>
<table data-type="dt" class="table table-striped table-bordered compact">
<thead>
<tr>
<th>Name</th>
<th>Position</th>
<th>Office</th>
<th>Age</th>
<th>Start date</th>
<th>Salary</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tiger Nixon 1</td>
<td>System Architect</td>
<td>Edinburgh</td>
<td>61</td>
<td>2011-04-25</td>
<td>$320,800</td>
</tr>
<tr>
<td>Garrett Winters 1</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>63</td>
<td>2011-07-25</td>
<td>$170,750</td>
</tr>
</tbody>
</table>
<table data-type="dt" class="table table-striped table-bordered compact">
<thead>
<tr>
<th>Name</th>
<th>Position</th>
<th>Office</th>
<th>Age</th>
<th>Start date</th>
<th>Salary</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tiger Nixon 2</td>
<td>System Architect</td>
<td>Edinburgh</td>
<td>61</td>
<td>2011-04-25</td>
<td>$280,800</td>
</tr>
<tr>
<td>Garrett Winters 2</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>63</td>
<td>2011-07-25</td>
<td>$590,750</td>
</tr>
</tbody>
</table>
</body>
</html>