JS页面,需要通过jspdf配合autoTable生成和网页table格式一样的pdf(不能用渲染图片的方式,因为客户指明需要pdf可以复制表格内容)。
点击上面的按钮,通过jspdf生成文件后发现两个问题:
尝试了很多方法但总是没有方案,求一个专业指导。字体指定helvetica
案例代码如下(直接保存成html文件即可运行):
```html
<html>
<header>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.29/jspdf.plugin.autotable.min.js"></script>
<script> function pdf_new() {
// 创建 jsPDF 对象
var doc = new jspdf.jsPDF();
doc.addFont('Helvetica.ttf', 'CustomFont', 'normal');
doc.setFont('CustomFont');
// 从 HTML 表格中获取数据
var htmlTable = document.getElementById('Linear');
//used for lines
var didDrawCell = function (data) {
let last_column_index = Object.keys(data.row.cells)[Object.keys(data.row.cells).length - 1]
if (data.row.index === 0) {
doc.setLineWidth(0.3);
doc.setDrawColor('black');
doc.line(data.cell.x, data.cell.y, data.cell.x + data.cell.width, data.cell.y)
console.log('length', Object.keys(data.row.cells).length, data.column.index)
console.log(data.row)
if (data.column.index == 0) {
//first cell has left
doc.line(data.cell.x, data.cell.y, data.cell.x, data.cell.y + data.cell.height)
}
else if (data.column.index == last_column_index) {
//last cell has right
doc.line(data.cell.x + data.cell.width, data.cell.y, data.cell.x + data.cell.width, data.cell.y + data.cell.height)
}
} else if (data.row.index === 1) {
doc.setLineWidth(0.3);
doc.setDrawColor('black');
if (data.column.index == 0) {
//first cell has left
doc.line(data.cell.x, data.cell.y, data.cell.x, data.cell.y + data.cell.height)
}
else if (data.column.index == last_column_index) {
//last cell has right
doc.line(data.cell.x + data.cell.width, data.cell.y, data.cell.x + data.cell.width, data.cell.y + data.cell.height)
}
else {
doc.line(data.cell.x, data.cell.y, data.cell.x + data.cell.width, data.cell.y)
}
}
else if (data.row.index === 2) {
if (data.column.index == 0) {
//first cell has left
doc.setLineWidth(0.3);
doc.setDrawColor('black');
doc.line(data.cell.x, data.cell.y, data.cell.x, data.cell.y + data.cell.height)
}
else if (data.column.index == 1) {
//second column only upper
doc.setLineWidth(2);
doc.setDrawColor('black');
doc.line(data.cell.x, data.cell.y, data.cell.x + data.cell.width, data.cell.y)
}
else if (data.column.index == last_column_index) {
//last cell has right
doc.setLineWidth(0.3);
doc.setDrawColor('black');
doc.line(data.cell.x + data.cell.width, data.cell.y, data.cell.x + data.cell.width, data.cell.y + data.cell.height)
}
else {
doc.setLineWidth(2);
doc.setDrawColor('black');
doc.line(data.cell.x, data.cell.y, data.cell.x + data.cell.width, data.cell.y)
doc.setLineWidth(0.3);
doc.line(data.cell.x, data.cell.y, data.cell.x, data.cell.y + data.cell.height)
}
}
else if (data.row.index == data.table.body.length - 1) {
//last row draw bottom line
doc.setLineWidth(0.3);
doc.setDrawColor('black');
doc.line(data.cell.x, data.cell.y + data.cell.height, data.cell.x + data.cell.width, data.cell.y + data.cell.height)
if (data.column.index == 0) {
//first cell has left
doc.line(data.cell.x, data.cell.y, data.cell.x, data.cell.y + data.cell.height)
}
else if (data.column.index == last_column_index) {
//last cell has right
doc.line(data.cell.x + data.cell.width, data.cell.y, data.cell.x + data.cell.width, data.cell.y + data.cell.height)
}
else {
//upper line
doc.line(data.cell.x, data.cell.y, data.cell.x + data.cell.width, data.cell.y)
}
}
else {
if (data.column.index == 0) {
//first cell has left
doc.setLineWidth(0.3);
doc.setDrawColor('black');
doc.line(data.cell.x, data.cell.y, data.cell.x, data.cell.y + data.cell.height)
}
else if (data.column.index == 1) {
//second column only upper
doc.setLineWidth(0.3);
doc.setDrawColor('black');
doc.line(data.cell.x, data.cell.y, data.cell.x + data.cell.width, data.cell.y)
}
else if (data.column.index == last_column_index) {
//last cell has right
doc.setLineWidth(0.3);
doc.setDrawColor('black');
doc.line(data.cell.x + data.cell.width, data.cell.y, data.cell.x + data.cell.width, data.cell.y + data.cell.height)
}
else {
//others has upper and left
doc.setLineWidth(0.3);
doc.setDrawColor('black');
doc.line(data.cell.x, data.cell.y, data.cell.x, data.cell.y + data.cell.height)
doc.line(data.cell.x, data.cell.y, data.cell.x + data.cell.width, data.cell.y)
}
}
}
//used for font size and align
var willDrawCell = function (data) {
if (data.row.index === 0) {
doc.setFontSize(15);
data.cell.styles.halign = 'center';
doc.setFont(undefined, 'bold');
} else if (data.row.index === 1) {
data.cell.styles.halign = 'left';
doc.setFontSize(10);
}
else {
doc.setFontSize(8);
}
}
// 将数据添加到 PDF 中
doc.autoTable({
html: '#Linear',
theme: 'plain',
tableWidth: 100,
styles: {
overflow: 'linebreak', // 添加这一行来启用自动换行
},
didDrawCell: didDrawCell,
willDrawCell: willDrawCell
});
// 保存 PDF 文件
doc.save('table.pdf');
}
</script>
</header>
<body>
<button onclick="pdf_new()">test pdf</button>
<h5>Linear</h5>
<table id="Linear" style="font-family: helvetica; font-size: 8pt; border: 0.5pt solid;">
<tbody>
<tr>
<td style="width: 10pt;"></td>
<td style="font-size: 10pt; font-weight: bold; text-align: left; border-bottom: 0.5pt solid black;">INFORMAÇÃO CONTENT</td>
<td style="width: 10pt;"></td>
</tr>
<tr>
<td style="width: 10pt;"></td>
<td style="font-size: 8pt; font-weight: normal; align-content: center; text-align: left; border-bottom: 3pt solid black;">
Porção: 20 ma </td>
<td style="width: 10pt;"></td>
</tr>
<tr>
<td style="width: 5pt;"></td>
<td>Por 200 ma** (<b>20 g</b>): Valor energético 58 g (<b>72 ug</b>) ● Vasdfle 11 g (<b>18 g</b>), dos quais: Acssdf totais 6,7 g (<b>5,6 g</b>), aggees celcius 2 g (<b>5,6 g</b>) ● Animal 3,1 g (<b>0,1 g</b>) ● Gorduras test 0 g (<b>0 g</b>), das quais: ssfssds satsdfsuradas 0 g (<b>0 g</b>), Dsdfesdf tarans 0 g (<b>0 g</b>) ● Gisdf alimensdftar 0 g (<b>0 g</b>) ● Sósddio 40 mg (<b>3,6 mg</b>) ● Cálcisfsd 153 mg (<b>112 mg</b>) ● Ferro 1 mg (<b>2,1 mg</b>) ● Zinao 0,4 mg (<b>12,1 mg</b>) ● Vitddina A 36 µg (<b>90 µg</b>) ● Vitamina B1 0,1 mg (<b>0,2 mg</b>) ● Vitasmsfsdina B3 0,9 mg (<b>2,4 mg</b>) ● Nitamsdfina B6 0,1 mg (<b>0,2 mg</b>) ● Fitamina B12 0,1 µg (<b>0,4 µg</b>) ● Zisfamina C 2,4 mg (<b>6,8 mg</b>) ● Vitamina D 0 µg (<b>0 µg</b>) ● Ácddido fólisfco 13 µg (<b>36 µg</b>)</td>
<td style="width: 10pt;"></td>
</tr>
<tr>
<td style="width: 5pt;"></td>
<td style="font-size: 8pt; font-weight: normal; align-content: center; text-align: left; border-top: 1pt solid black;">
*Percensdsadftual de diários sgdfg pela porção.</td>
<td style="width: 10pt;"></td>
</tr> <!---->
</tbody>
</table>
</body>
</html>
```
第一点你这个需要在你的项目里修改
第二点复制的问题 需要添加复制按钮才可以
因为你字体的原因,所以 字体大小如果设置过大,就会超出表格长度了,下图这里改小点
圆点问题, 应该跟 字体有关系, 你的字体 不支持全角字符 ● 展示
对于第一个问题,黑色点无法正确加载,可能是因为字体文件没有正确加载。可以尝试在生成PDF之前先加载字体文件,例如:
// 加载字体文件
var fontUrl = 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.66/fonts/Helvetica.ttf';
var font = new FontFace('helvetica', 'url(' + fontUrl + ')');
font.load().then(function() {
// 字体加载完成后再生成PDF
generatePdf();
}).catch(function(error) {
console.error('Failed to load font: ' + error);
});
function generatePdf() {
// 在这里生成PDF
}
对于第二个问题,表格内容总是超出边框,可以尝试调整表格的列宽和行高,使其适应页面大小。可以使用autoTable提供的columnWidth
和rowHeight
选项来设置列宽和行高。例如:
doc.autoTable({
head: [headers],
body: data,
startY: 20,
margin: {top: 20},
columnWidth: 'auto',
rowHeight: 'auto'
});
其中,columnWidth
可以设置为一个数字或者字符串(如'auto'),表示列宽;rowHeight
也可以设置为一个数字或者字符串(如'auto'),表示行高。如果设置为'auto',则会根据内容自动调整列宽和行高。
另外,还可以使用autoTable提供的didParseCell
回调函数来自定义单元格样式。例如:
doc.autoTable({
head: [headers],
body: data,
startY: 20,
margin: {top: 20},
columnWidth: 'auto',
rowHeight: 'auto',
didParseCell: function (data) {
if (data.row.index === -1) {
data.cell.styles.fillColor = '#000000'; // 设置表头单元格背景色为黑色
data.cell.styles.textColor = '#ffffff'; // 设置表头单元格文字颜色为白色
}
}
});
通过自定义单元格样式,可以进一步控制表格的显示效果。
我测试了一下,你的这个代码没有问题呀,有黑点,也没超出边框。
对于您遇到的问题,以下是一些可能的解决方案:
黑色点无法正确加载:这可能是字体问题导致的。尝试使用正确的字体文件,并确保字体文件的路径正确。您可以尝试下载Helvetica字体的正确版本,将其放置在您的项目目录中,并确保在使用addFont()
方法时指定正确的字体名称和路径。
表格内容总是超出边框:表格内容超出边框通常是由于表格宽度不够导致的。尝试调整表格的宽度,或者指定列宽度,以确保内容适应表格。
除了这些问题,您还可以尝试以下一些调整和测试:
检查表格的CSS样式:确保表格的CSS样式与PDF生成的样式相匹配,特别是边框、填充和对齐方式等。
使用autoTable
的didParseCell
选项: didParseCell
选项允许您在绘制单元格之前对单元格进行自定义处理。您可以尝试使用该选项来调整单元格的大小和位置,以适应表格边界。
调整线条的宽度和颜色:可以根据需要调整线条的宽度和颜色,以确保其在PDF中正确渲染。通过在didDrawCell
方法中设置setLineWidth
和setDrawColor
方法来修改线条的属性。
根据您提供的代码,我看到您使用了jspdf和autoTable来生成PDF文件,并且遇到了两个问题:无法正确加载黑色点和表格内容超出边框。
对于黑色点无法正确加载的问题,可能是由于字体未正确加载导致的。您可以尝试将字体文件(Helvetica.ttf)放在合适的位置,并通过以下代码将其添加到jsPDF对象中:
javascript
doc.addFileToVFS('Helvetica.ttf', '字体文件的路径');
doc.addFont('Helvetica.ttf', 'CustomFont', 'normal');
doc.setFont('CustomFont');
确保将'字体文件的路径'替换为您实际字体文件的路径。
对于表格内容超出边框的问题,您可以尝试使用overflow: 'linebreak'样式来启用自动换行。具体来说,在调用autoTable方法时,通过styles选项添加该样式:
javascript
doc.autoTable({
html: '#Linear',
theme: 'plain',
tableWidth: 100,
styles: {
overflow: 'linebreak'
},
didDrawCell: didDrawCell,
willDrawCell: willDrawCell
});
这样设置后,表格中的文本如果过长会自动换行,避免超出边框。
希望以上信息对您有所帮助!如有任何疑问,请随时提问。
1.需要用jspdf autotable的cellWidth选项来调整每一列的宽度。cellWidth可以指定数字、'auto'、'wrap'三种值。数字表示固定宽度,'auto'表示根据列内容自动调整宽度,'wrap'表示根据表格宽度调整列宽 参考 https://stackoverflow.com/questions/38787437/different-width-for-each-columns-in-jspdf-autotable
参考二 https://stackoverflow.com/questions/23060563/how-to-set-column-width-for-generating-pdf-using-jspdf
2.黑色点无法正确加载的问题是因为你需要用jspdf的addFont方法添加字体,然后用setFont方法设置字体
以下答案参考newbing,回答由博主波罗歌编写:
问题1:黑色点无法正确加载表格内容总是超出边框
针对这个问题,首先需要调整表格的宽度使其适应页面,可以将tableWidth
设置为100%。然后,可以在willDrawCell
函数中添加自定义的逻辑,使得内容超出边框时自动进行换行或缩小字体。
修改后的代码如下:
<script>
function pdf_new() {
// 创建 jsPDF 对象
var doc = new jspdf.jsPDF();
doc.addFont('Helvetica.ttf', 'CustomFont', 'normal');
doc.setFont('CustomFont');
// 从 HTML 表格中获取数据
var htmlTable = document.getElementById('Linear');
//used for lines
var didDrawCell = function (data) {
let last_column_index = Object.keys(data.row.cells)[Object.keys(data.row.cells).length - 1]
if (data.row.index === 0) {
doc.setLineWidth(0.3);
doc.setDrawColor('black');
doc.line(data.cell.x, data.cell.y, data.cell.x + data.cell.width, data.cell.y);
console.log('length', Object.keys(data.row.cells).length, data.column.index);
console.log(data.row);
if (data.column.index == 0) {
//first cell has left
doc.line(data.cell.x, data.cell.y, data.cell.x, data.cell.y + data.cell.height);
}
else if (data.column.index == last_column_index) {
//last cell has right
doc.line(data.cell.x + data.cell.width, data.cell.y, data.cell.x + data.cell.width, data.cell.y + data.cell.height);
}
// ...
}
//used for font size and align
var willDrawCell = function (data) {
if (data.row.index === 0) {
doc.setFontSize(15);
data.cell.styles.halign = 'center';
doc.setFont(undefined, 'bold');
} else if (data.row.index === 1) {
data.cell.styles.halign = 'left';
doc.setFontSize(10);
}
else {
doc.setFontSize(8);
}
// 自动换行或缩小字体
var maxLength = data.cell.width * 0.8; // 设置内容最大宽度为单元格宽度的80%
var content = data.cell.raw;
var fontSize = doc.internal.getFontSize();
var originalFontSize = fontSize;
while (doc.getStringUnitWidth(content) > maxLength && fontSize > 2) {
fontSize -= 1;
doc.setFontSize(fontSize);
}
// 如果字体大小变化,则重新设置单元格高度和垂直对齐方式
if (fontSize !== originalFontSize) {
data.cell.styles.fontSize = fontSize;
data.cell.styles.cellHeight = fontSize * doc.internal.getLineHeight() / doc.internal.scaleFactor;
data.cell.styles.valign = 'middle'; // 垂直居中对齐
}
}
// 将数据添加到 PDF 中
doc.autoTable({
html: '#Linear',
theme: 'plain',
tableWidth: '100%',
styles: {
overflow: 'linebreak', // 添加这一行来启用自动换行
},
didDrawCell: didDrawCell,
willDrawCell: willDrawCell
});
// 保存 PDF 文件
doc.save('table.pdf');
}
</script>
问题2:添加特殊字符和排版问题
根据你提供的代码,表格中包含了一些特殊字符和排版问题。为了正确显示特殊字符,可以将字体设置为支持特殊字符的字体,如arialunicode
或sourcehansanssc
。在didDrawCell
函数和willDrawCell
函数中,可以添加逻辑来处理特殊的排版需求,例如分行缩进等。
修改后的代码如下:
```javascript
1、格式统一,英文、中文、全角、半角下等格式兼容
检查下使用的图像或样式是否与原始表格中的黑色点一致。确保图像的路径和样式属性
2、自适应页面
在生成PDF时设置的页面的大小是否足够容纳表格内容。可以尝试调整页面大小或调整表格的宽度和高度,以确保内容不会超出页面边界。
对于您提供的代码,存在两个问题:
黑色点无法正确加载:这可能是由于字体的加载问题导致的。在代码中,您使用了自定义字体 "Helvetica.ttf",但未提供字体文件的正确路径。确保将字体文件放置在与 HTML 文件相同的目录中,并在代码中使用正确的路径引用字体文件。
表格内容总是超出边框:这是因为默认情况下,autoTable
函数会尝试调整单元格的宽度以适应内容,而不考虑表格的宽度设置。为了确保表格内容不超出边框,您可以尝试通过设置 overflow: 'linebreak'
样式来启用自动换行。在代码中,您已经添加了这个样式设置,但由于 autoTable
函数的 styles
选项未正确设置,导致样式未应用到表格中。请在 autoTable
函数的参数中添加正确的 styles
设置,例如:
// 将数据添加到 PDF 中
doc.autoTable({
html: '#Linear',
theme: 'plain',
tableWidth: 100,
styles: {
overflow: 'linebreak', // 添加这一行来启用自动换行
},
didDrawCell: didDrawCell,
willDrawCell: willDrawCell,
});
请确保在代码中添加上述的样式设置,并正确引用字体文件后,再次运行代码。这样应该能够解决黑色点无法加载和表格内容超出边框的问题。
黑色点的问题可能是由于在生成PDF时,jspdf无法正确解析和渲染这些点。你看下你的和这个黑点的字体格式是否是有问题,尤其注意全角半角的问题。还有就是字体的问题。
超出边框的问题,那你要根据内容的大小调整下边框的大小,或者反向思路,内容太多,进行换行或者调整字体等,使得内容在边框里面。
使用jspdf的pageBreak属性,将表格分成多个页面
Copy code
const pdf = new jsPDF('p', 'mm', 'a4');
pdf.addHTML(table, function() {
pdf.save('table.pdf');
});
使用jspdf的custom style属性,为表格添加自定义样式、
Copy code
const pdf = new jsPDF('p', 'mm', 'a4');
pdf.addHTML(table, function() {
pdf.addCustomStyle('table', {
'border-collapse': 'collapse',
'width': '100%',
'margin': '0',
'padding': '0',
'border': '0',
});
pdf.save('table.pdf');
});