React 将 Div 和 Table 组件转换为具有多页和 CSS 的 PDF
React Convert Div and Table Component Into PDF With Multiple Pages and CSS
正如标题所说,我需要能够将 table 转换为具有跨多个页面的 header 的 pdf(就像我在打印时所做的那样)。
我找到了几个关于如何将 React 组件转换为 pdf 文件的资源。但是 none 涵盖了要求 component/table 分布在多个页面和导入您也拥有的 CSS 的组合。我使用 react-to-print 库将其用于打印,但我似乎找不到任何 pdf 文件。 react-pdf 库形式仍然不能使用 html 元素。
完整代码 - https://codesandbox.io/s/react-table-to-pdf-m15em?file=/src/App.js
pdf 函数...
exportPdf = () => {
const state = this.props.listOfStates.find(state => state.id === this.state.selectedStateId);
const school = this.props.listOfSchools.find(school => school.id === this.state.selectedSchoolId);
Promise.resolve(this.setState({ ...this.state, selectedStateNamePdf: state.stateName, selectedSchoolNamePdf: school.schoolName }))
.then(() => {
const input = document.getElementById('pdf-element');
html2canvas(input)
.then((canvas) => {
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF();
pdf.addImage(imgData, 'JPEG', 0, 0);
pdf.addPage();
pdf.addImage(imgData, 'JPEG', 0, 0);
pdf.save("download.pdf");
})
;
})
}
pdf 组件...
class PdfReportContent extends Component {
render(){
const { selectedReportDetails, stateName, schoolName, startDate, endDate } = this.props;
return (
<div id="pdf-element" style={{maxWidth: "210mm", width: "100%", height: "100%", position: "relative", margin: "0"}}>
<div style={{display: "block"}}>
<div style={{width: "100%", display: "flex", justifyContent: "space-between", padding: "1vh 2.5vh 0"}}>
<div>
<h2 className="header-title-one">SCHOOL</h2>
<h2 className="header-title-two">REPORT</h2>
</div>
<div style={{display: "flex"}}>
<div style={{display: "inline-block", textAlign: "right"}}>
<h5>{stateName}</h5>
<h5>{schoolName}</h5>
<p>{startDate} - {endDate}</p>
</div>
</div>
</div>
<hr />
<h3 style={{margin: "10px 0 0 2.5vh"}}>REPORT RESULTS</h3>
</div>
<div id="print-list-body">
{selectedReportDetails.map((classDetails, indexOne) =>
<div key={indexOne} style={{maxWidth: "200mm", width: "100%", margin: "40px auto 0 auto", boxSizing: "border-box"}}>
<h2 style={{marginBottom: "10px", color: "#01A3E0"}}>{classDetails.className}</h2>
{classDetails.classes.map((dateTable, indexTwo, classes) =>
<table key={indexTwo} className="tbl-reports-list">
<tbody>
<tr>
<th>{dateTable.date}</th>
<th>Students</th>
<th>Grades</th>
<th>Assignment</th>
<th>Attendance</th>
</tr>
{dateTable.instructors.map((instructor, indexThree, instructorRows) =>
instructor.students.map((row, indexFour, studentRows) =>
indexTwo === classes.length-1 ?
<tr key={indexFour} style={indexFour === studentRows.length-1 ? { borderBottom: "2px solid #01A3E0"} : {}}>
{indexFour === 0 ?
<td>
<h5>{instructor.instructorName}</h5>
</td> : <td />
}
<td style={{backgroundColor: "#ffffff"}}>{row.name}</td>
<td style={row.isHonorStudent ? {backgroundColor: "#ffffff"} : {backgroundColor: "#ffedbc"}}>{row.grade}</td>
<td style={{backgroundColor: "#ffffff"}}>{row.assignment}</td>
<td style={{backgroundColor: "#ffffff"}}>{row.attendance}</td>
</tr> :
<tr key={indexFour} style={indexFour === studentRows.length-1 && indexThree !== instructorRows.length-1 ? { borderBottom: "2px solid #01A3E0"} : {}}>
{indexFour === 0 ?
<td>
<h5>{instructor.instructorName}</h5>
</td> : <td />
}
<td style={{backgroundColor: "#ffffff"}}>{row.name}</td>
<td style={row.isHonorStudent ? {backgroundColor: "#ffffff"} : {backgroundColor: "#ffedbc"}}>{row.grade}</td>
<td style={{backgroundColor: "#ffffff"}}>{row.assignment}</td>
<td style={{backgroundColor: "#ffffff"}}>{row.attendance}</td>
</tr>
)
)}
</tbody>
</table>
)}
</div>
)}
</div>
</div>
);
}
}
重现问题的步骤:
- Select 两个下拉列表中的任何项目
- 点击生成报告
- 单击下载 PDF
- 打开 pdf 并注意第一页和第二页如何显示相同的内容,其余 table 数据丢失。
如果有人可以在 codesandbox link 中 fork 项目并告诉我我缺少什么,将不胜感激。
jsPdf 有一个渲染方法 html,您可以使用它而不是用图像手动创建文档,这是对您的代码的必要更改:
...
const input = document.getElementById("pdf-element");
const pdf = new jsPDF({ unit: "px", format: "letter", userUnit: "px" });
pdf.html(input, { html2canvas: { scale: 0.57 } }).then(() => {
pdf.save("test.pdf");
});
...
注意到我在 jsPdf 对象创建和调用 .hmtl()
时调整了一些配置,出于某种原因 pdf 被放大了,这就是我为 html2canvas 添加缩放选项的原因(这也可能是 platform/browser 家属)
这是经过更改的分支 https://codesandbox.io/s/react-table-to-pdf-forked-2iri9
您可以使用此代码:
...
const input = document.getElementById("pdf-element");
const pdf = new jsPDF('p', 'pt', 'a4');
pdf.html(input).then(() => {
pdf.save('test.pdf');
});
...
正如标题所说,我需要能够将 table 转换为具有跨多个页面的 header 的 pdf(就像我在打印时所做的那样)。
我找到了几个关于如何将 React 组件转换为 pdf 文件的资源。但是 none 涵盖了要求 component/table 分布在多个页面和导入您也拥有的 CSS 的组合。我使用 react-to-print 库将其用于打印,但我似乎找不到任何 pdf 文件。 react-pdf 库形式仍然不能使用 html 元素。
完整代码 - https://codesandbox.io/s/react-table-to-pdf-m15em?file=/src/App.js
pdf 函数...
exportPdf = () => {
const state = this.props.listOfStates.find(state => state.id === this.state.selectedStateId);
const school = this.props.listOfSchools.find(school => school.id === this.state.selectedSchoolId);
Promise.resolve(this.setState({ ...this.state, selectedStateNamePdf: state.stateName, selectedSchoolNamePdf: school.schoolName }))
.then(() => {
const input = document.getElementById('pdf-element');
html2canvas(input)
.then((canvas) => {
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF();
pdf.addImage(imgData, 'JPEG', 0, 0);
pdf.addPage();
pdf.addImage(imgData, 'JPEG', 0, 0);
pdf.save("download.pdf");
})
;
})
}
pdf 组件...
class PdfReportContent extends Component {
render(){
const { selectedReportDetails, stateName, schoolName, startDate, endDate } = this.props;
return (
<div id="pdf-element" style={{maxWidth: "210mm", width: "100%", height: "100%", position: "relative", margin: "0"}}>
<div style={{display: "block"}}>
<div style={{width: "100%", display: "flex", justifyContent: "space-between", padding: "1vh 2.5vh 0"}}>
<div>
<h2 className="header-title-one">SCHOOL</h2>
<h2 className="header-title-two">REPORT</h2>
</div>
<div style={{display: "flex"}}>
<div style={{display: "inline-block", textAlign: "right"}}>
<h5>{stateName}</h5>
<h5>{schoolName}</h5>
<p>{startDate} - {endDate}</p>
</div>
</div>
</div>
<hr />
<h3 style={{margin: "10px 0 0 2.5vh"}}>REPORT RESULTS</h3>
</div>
<div id="print-list-body">
{selectedReportDetails.map((classDetails, indexOne) =>
<div key={indexOne} style={{maxWidth: "200mm", width: "100%", margin: "40px auto 0 auto", boxSizing: "border-box"}}>
<h2 style={{marginBottom: "10px", color: "#01A3E0"}}>{classDetails.className}</h2>
{classDetails.classes.map((dateTable, indexTwo, classes) =>
<table key={indexTwo} className="tbl-reports-list">
<tbody>
<tr>
<th>{dateTable.date}</th>
<th>Students</th>
<th>Grades</th>
<th>Assignment</th>
<th>Attendance</th>
</tr>
{dateTable.instructors.map((instructor, indexThree, instructorRows) =>
instructor.students.map((row, indexFour, studentRows) =>
indexTwo === classes.length-1 ?
<tr key={indexFour} style={indexFour === studentRows.length-1 ? { borderBottom: "2px solid #01A3E0"} : {}}>
{indexFour === 0 ?
<td>
<h5>{instructor.instructorName}</h5>
</td> : <td />
}
<td style={{backgroundColor: "#ffffff"}}>{row.name}</td>
<td style={row.isHonorStudent ? {backgroundColor: "#ffffff"} : {backgroundColor: "#ffedbc"}}>{row.grade}</td>
<td style={{backgroundColor: "#ffffff"}}>{row.assignment}</td>
<td style={{backgroundColor: "#ffffff"}}>{row.attendance}</td>
</tr> :
<tr key={indexFour} style={indexFour === studentRows.length-1 && indexThree !== instructorRows.length-1 ? { borderBottom: "2px solid #01A3E0"} : {}}>
{indexFour === 0 ?
<td>
<h5>{instructor.instructorName}</h5>
</td> : <td />
}
<td style={{backgroundColor: "#ffffff"}}>{row.name}</td>
<td style={row.isHonorStudent ? {backgroundColor: "#ffffff"} : {backgroundColor: "#ffedbc"}}>{row.grade}</td>
<td style={{backgroundColor: "#ffffff"}}>{row.assignment}</td>
<td style={{backgroundColor: "#ffffff"}}>{row.attendance}</td>
</tr>
)
)}
</tbody>
</table>
)}
</div>
)}
</div>
</div>
);
}
}
重现问题的步骤:
- Select 两个下拉列表中的任何项目
- 点击生成报告
- 单击下载 PDF
- 打开 pdf 并注意第一页和第二页如何显示相同的内容,其余 table 数据丢失。
如果有人可以在 codesandbox link 中 fork 项目并告诉我我缺少什么,将不胜感激。
jsPdf 有一个渲染方法 html,您可以使用它而不是用图像手动创建文档,这是对您的代码的必要更改:
...
const input = document.getElementById("pdf-element");
const pdf = new jsPDF({ unit: "px", format: "letter", userUnit: "px" });
pdf.html(input, { html2canvas: { scale: 0.57 } }).then(() => {
pdf.save("test.pdf");
});
...
注意到我在 jsPdf 对象创建和调用 .hmtl()
时调整了一些配置,出于某种原因 pdf 被放大了,这就是我为 html2canvas 添加缩放选项的原因(这也可能是 platform/browser 家属)
这是经过更改的分支 https://codesandbox.io/s/react-table-to-pdf-forked-2iri9
您可以使用此代码:
...
const input = document.getElementById("pdf-element");
const pdf = new jsPDF('p', 'pt', 'a4');
pdf.html(input).then(() => {
pdf.save('test.pdf');
});
...