
本文介绍通过自定义 pdf 导出样式与结构,解决 datatables 中宽表(如 12 列)导出 pdf 时内容横向溢出的问题,核心方案是结合 `pdfmake` 的 `customize` 钩子动态拆分行、控制列布局,并辅以响应式 css 优化打印效果。
DataTable 默认的 pdfHtml5 按钮使用 pdfMake 渲染 PDF,但其原生行为会将整行强行压缩进一页宽度,导致文字重叠或截断——尤其当表格列数较多(如您的 12 列)时,仅靠“跳过一行”无法根本解决问题。真正有效的做法是逻辑分组 + 视觉换行:将每行数据按列切分为多个逻辑段(例如前6列一组、后6列一组),在 PDF 中以连续的、带标题标识的块状结构呈现。
以下是完整实现方案:
✅ 步骤一:启用 customize 钩子,重构 PDF 内容结构
在按钮配置中添加 customize 函数,拦截原始 doc 对象并重写 content:
{
extend: 'pdfHtml5',
orientation: 'landscape',
pageSize: 'LEGAL',
text: 'PDF',
customize: function(doc) {
// 获取原始表格数据(已渲染的 body 行)
const rows = doc.content[1].table.body;
const newBody = [];
rows.forEach((row, i) => {
// 跳过表头(通常第一行是 header)
if (i === 0) {
newBody.push(row);
return;
}
// 将单行 12 列拆为两个子行:[0–5] 和 [6–11]
const firstHalf = row.slice(0, 6).map(cell => ({
...cell,
margin: [0, 2, 0, 2], // 微调垂直间距
}));
const secondHalf = row.slice(6, 12).map(cell => ({
...cell,
margin: [0, 2, 0, 2],
}));
// 添加分隔空行(视觉换行)
newBody.push(firstHalf);
newBody.push([
{ text: '', colSpan: 6, border: [false, false, false, false], margin: [0, 4, 0, 4] }
]);
newBody.push(secondHalf);
newBody.push([
{ text: '', colSpan: 6, border: [false, false, false, false], margin: [0, 8, 0, 8] }
]);
});
// 替换原表格 body
doc.content[1].table.body = newBody;
// 可选:缩小字体提升可读性
doc.styles.tableBody.fontSize = 8;
doc.styles.tableHeader.fontSize = 9;
}
}✅ 步骤二:增强可读性 —— 添加分组标识(推荐)
为避免上下两段混淆,可在第二段前插入轻量标题,例如:
newBody.push([
{
text: '【续】第 ' + (i) + ' 行(列 7–12)',
fontSize: 7,
color: '#666',
colSpan: 6,
margin: [0, 6, 0, 2]
}
]);
newBody.push(secondHalf);✅ 步骤三:配合打印样式(防御性补充)
虽然 customize 已主导 PDF 结构,但仍建议添加打印专用 CSS,确保浏览器内预览与导出一致:
⚠️ 注意事项
- pdfHtml5 依赖 vfs_fonts.js,请确保该文件加载成功(控制台无 Cannot find font 报错);
- 若列内容含 HTML(如图标、按钮),需在 customize 中先用 $(row).text() 提取纯文本,否则 pdfMake 会报错;
- pageSize: 'LEGAL'(约 14×8.5 英寸)适合宽表,但若仍显拥挤,可改用 'A3' 或自定义尺寸:pageSize: { width: 1150, height: 842 }(单位:pt);
- 此方案不修改原始 DOM,完全在导出阶段处理,不影响页面交互与 Excel 导出。
通过上述结构化拆分,您将获得一份清晰、专业、无溢出的 PDF 报表——不再是“勉强塞进一页”,而是“有逻辑地分层呈现”。










