react-pdf/renderer IE 需要很长时间才能生成 blob 以下载 pdf
react-pdf/renderer IE takes very long time to generate blob to download pdf
async function saveBlob() {
const doc = <TableDocument/>;
const asPdf = pdf([]);
await asPdf.updateContainer(doc);
const blob = await asPdf.toBlob();
saveAs(blob, 'instructions.pdf');
}
return (
<IconButton
onClick={() => saveBlob()}>
</IconButton>
);
这就是我尝试通过获取 blob 然后下载它来生成我的 pdf 文档的方式。我只使用 reactJS 在客户端做所有事情。
在 Chrome 和 Edge 浏览器上只需要 3-4 秒,但在 IE 上大约需要 30-40 秒。它是一个 3 页的 pdf 文档,带有简单的 table(对于单页 IE 大约需要 8-9 秒)。
甚至在使用 async await 之后它也会阻塞 UI。
任何有助于减少在 IE 上生成 pdf 的时间的帮助将不胜感激。
我找到了 pdfmake(https://pdfmake.github.io/docs/0.1/) 库,它从客户端生成 pdf 的速度非常快。在 IE 上也只需 2 秒即可生成 pdf。
function TablePDF(t, headerGroups, rows, pageName, messageTitle, messageBody, fontLocale, fontMargin, rowFlag) {
const moreRows = [...rows];
const createTableHeader = col => {
const val = t(col.Header);
return { text: val && val.replace(/<\/br>|<br>/g, '\n'), style: 'tableHeader' };
};
const createTableRow = row => {
const rowElement = [];
Object.entries(row).map(([key, val]) => {
if (key === 'notes' || (rowFlag && key === 'fileNameFileReference')) return null;
const rowCellFormatted =
key === 'instructionStatus'
? mapInstructionStatus(val)
: key === 'instructionType'
? t(mapInstructionTypeStoreData(val))
: val;
const cellText =
(rowCellFormatted &&
(typeof rowCellFormatted === 'string' && rowCellFormatted.replace(/<\/br>|<br>/g, '\n'))) ||
rowCellFormatted ||
'';
rowElement.push({
text: cellText,
margin: [5, fontMargin(getLanguageFont(cellText)), 5, 5],
font: getLanguageFont(cellText)
});
return null;
});
return rowElement;
};
const getTableHeader = () => {
const arrOfHeader =
headerGroups &&
headerGroups.length &&
headerGroups[0].headers
.filter(col => {
if (
col.render('Header') === 'ila.notes' ||
(rowFlag && col.render('Header') === 'ila.fileNameFileReference')
) {
return false;
}
return true;
})
.map((col, index) => createTableHeader(col, index));
return arrOfHeader;
};
const arrOfHeader = getTableHeader();
const getTableRows = () => moreRows.map(row => createTableRow(row.values));
const pdfNote = t('ila.pdfNote');
const mapInstructionStatus = status => {
let statusToReturn = '';
const INSTRUCTION_STATUS = ROW_INSTRUCTION_STATUS;
switch (status) {
case 'PA':
statusToReturn = INSTRUCTION_STATUS[0].label;
break;
case 'RA':
statusToReturn = INSTRUCTION_STATUS[1].label;
break;
case 'P2':
statusToReturn = INSTRUCTION_STATUS[2].label;
break;
case 'R2':
statusToReturn = INSTRUCTION_STATUS[3].label;
break;
case 'P3':
statusToReturn = INSTRUCTION_STATUS[4].label;
break;
case 'R3':
statusToReturn = INSTRUCTION_STATUS[5].label;
break;
case 'P4':
statusToReturn = INSTRUCTION_STATUS[6].label;
break;
case 'P5':
statusToReturn = INSTRUCTION_STATUS[7].label;
break;
case 'RB':
statusToReturn = 'ila.receivedByBank';
break;
case 'JB':
statusToReturn = 'ila.rejectedByBank';
break;
case 'JC':
statusToReturn = 'ila.rejectedByCustomer';
break;
case 'RF':
statusToReturn = 'ila.receivedFwdInstr';
break;
default:
statusToReturn = t(`ila.instructionStatus_${status}`) ? `ila.instructionStatus_${status}` : '';
break;
}
return t(statusToReturn);
};
const mapInstructionTypeStoreData = type => {
switch (type) {
case 'C0':
case 'C1':
case 'PP':
return 'ila.pp';
case 'CS':
case 'COS':
return 'ila.cos';
case 'AP':
case 'ACH':
case 'APC':
return 'ila.achCredit';
case 'AD':
case 'APD':
return 'ila.achDebit';
default:
return type;
}
};
const tableDoc = {
pageOrientation: 'landscape',
pageMargins: [25, 74, 25, 60],
footer: (currentPage, pageCount) => PDFFooter(pageName, pageCount, currentPage),
header: () => PDFHeader(fontMargin(fontLocale), pageName),
content: [
{
text: [{ text: messageTitle, bold: true, color: 'black' }, { text: messageBody }, '\n', { text: pdfNote }],
style: 'note'
},
{
style: 'tableStyle',
table: {
headerRows: 1,
dontBreakRows: true,
body: [arrOfHeader, ...getTableRows()],
widths:
arrOfHeader.length === 9
? ['13.3%', '11.3%', '11.3%', '13.3%', '12.3%', '9.1%', '9.1%', '8.6%', '11.6%']
: ['12.8%', '12.8%', '14.8%', '13.8%', '10.6%', '10.6%', '11.4%', '13.1%']
},
layout: {
vLineWidth: () => 1.2,
hLineWidth: hLineIndex => (hLineIndex === 1 ? 0 : 1.2),
hLineColor: () => '#E4E8EA',
// eslint-disable-next-line no-confusing-arrow
vLineColor: (i, node, rowIndex) =>
rowIndex === 0 || (i === 0 || i === arrOfHeader.length) ? 'white' : '#E4E8EA',
fillColor: rowIndex => (rowIndex === 0 ? '#E4E8EA' : null)
}
}
],
styles: {
tableStyle: {
margin: [0, fontMargin(fontLocale), 0, 20]
},
tableHeader: {
bold: true,
color: 'black',
margin: [5, fontMargin(fontLocale), 5, 5]
},
note: {
lineHeight: 2,
italics: false
}
},
defaultStyle: {
columnGap: 10,
font: fontLocale,
color: '#333333',
fontSize: 8
}
};
return tableDoc;
}
export default TablePDF;
const date = new Date();
const gmtString = date.toGMTString();
const finalDate =
JSON.stringify(gmtString).slice(6, 17) +
',' +
JSON.stringify(gmtString).slice(17, 23) +
JSON.stringify(gmtString).slice(26, 30);
const PDF_Footer = (pageName, totalPages, pageNumber, reference) => ({
margin: [30, 20, 30, 10],
stack: [
{
table: {
headerRows: 1,
widths: ['*'],
body: [[''], ['']]
},
layout: {
hLineWidth: i => (i === 0 ? 1 : 0),
vLineWidth: () => 0,
hLineColor: () => 'black'
}
},
{
columns: [
finalDate + ' | ' + pageName + (reference || ''),
{
text: pageNumber && totalPages && `Page ${pageNumber} of ${totalPages}`,
alignment: 'right'
}
]
}
],
color: '#333333',
bold: false
});
export default PDF_Footer;
export function getLanguageFont(text) {
const universal = /^[a-zA-Z0-9_\-/.!@#$%^&*' 'wığüşöçĞÜŞÖÇİÀ-ÿ/]+$/;
const arabic = /[\u0600-\u06FF]/;
const hebrew = /[\u0590-\u05FF]/;
const greek = /[\u0370-\u03ff\u1f00-\u1fff]/;
const japanese = /[\u3000-\u303f\u3040-\u309f\u30a0-\u30ff\uff00-\uff9f\u4e00-\u9faf\u3400-\u4dbf]/;
const korean = /[\u3130-\u318F\uAC00-\uD7AF]/g;
const russian = /[\u0401\u0451\u0410-\u044f]/;
const vietnamese = /^[a-zA-ZÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂẾưăạảấầẩẫậắằẳẵặẹẻẽềềểếỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵỷỹ\s\W|_]+$/;
const chinese = /[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uff66-\uff9f]/;
if (universal.test(text)) {
return 'UniverseNextHSBC';
} else if (arabic.test(text)) {
return 'arabicFont';
} else if (hebrew.test(text)) {
return 'hebrewFont';
} else if (greek.test(text)) {
return 'hebrewFont';
} else if (japanese.test(text)) {
return 'chineseSimple';
} else if (korean.test(text)) {
return 'korean';
} else if (vietnamese.test(text)) {
return 'vietnamese';
} else if (chinese.test(text)) {
return 'chineseSimple';
}
return 'UniverseNextHSBC';
}
pdfMake.createPdf(tableDoc, null, fontCategories).download(('file.pdf', () => setDownloading(false)));
async function saveBlob() {
const doc = <TableDocument/>;
const asPdf = pdf([]);
await asPdf.updateContainer(doc);
const blob = await asPdf.toBlob();
saveAs(blob, 'instructions.pdf');
}
return (
<IconButton
onClick={() => saveBlob()}>
</IconButton>
);
这就是我尝试通过获取 blob 然后下载它来生成我的 pdf 文档的方式。我只使用 reactJS 在客户端做所有事情。
在 Chrome 和 Edge 浏览器上只需要 3-4 秒,但在 IE 上大约需要 30-40 秒。它是一个 3 页的 pdf 文档,带有简单的 table(对于单页 IE 大约需要 8-9 秒)。
甚至在使用 async await 之后它也会阻塞 UI。 任何有助于减少在 IE 上生成 pdf 的时间的帮助将不胜感激。
我找到了 pdfmake(https://pdfmake.github.io/docs/0.1/) 库,它从客户端生成 pdf 的速度非常快。在 IE 上也只需 2 秒即可生成 pdf。
function TablePDF(t, headerGroups, rows, pageName, messageTitle, messageBody, fontLocale, fontMargin, rowFlag) {
const moreRows = [...rows];
const createTableHeader = col => {
const val = t(col.Header);
return { text: val && val.replace(/<\/br>|<br>/g, '\n'), style: 'tableHeader' };
};
const createTableRow = row => {
const rowElement = [];
Object.entries(row).map(([key, val]) => {
if (key === 'notes' || (rowFlag && key === 'fileNameFileReference')) return null;
const rowCellFormatted =
key === 'instructionStatus'
? mapInstructionStatus(val)
: key === 'instructionType'
? t(mapInstructionTypeStoreData(val))
: val;
const cellText =
(rowCellFormatted &&
(typeof rowCellFormatted === 'string' && rowCellFormatted.replace(/<\/br>|<br>/g, '\n'))) ||
rowCellFormatted ||
'';
rowElement.push({
text: cellText,
margin: [5, fontMargin(getLanguageFont(cellText)), 5, 5],
font: getLanguageFont(cellText)
});
return null;
});
return rowElement;
};
const getTableHeader = () => {
const arrOfHeader =
headerGroups &&
headerGroups.length &&
headerGroups[0].headers
.filter(col => {
if (
col.render('Header') === 'ila.notes' ||
(rowFlag && col.render('Header') === 'ila.fileNameFileReference')
) {
return false;
}
return true;
})
.map((col, index) => createTableHeader(col, index));
return arrOfHeader;
};
const arrOfHeader = getTableHeader();
const getTableRows = () => moreRows.map(row => createTableRow(row.values));
const pdfNote = t('ila.pdfNote');
const mapInstructionStatus = status => {
let statusToReturn = '';
const INSTRUCTION_STATUS = ROW_INSTRUCTION_STATUS;
switch (status) {
case 'PA':
statusToReturn = INSTRUCTION_STATUS[0].label;
break;
case 'RA':
statusToReturn = INSTRUCTION_STATUS[1].label;
break;
case 'P2':
statusToReturn = INSTRUCTION_STATUS[2].label;
break;
case 'R2':
statusToReturn = INSTRUCTION_STATUS[3].label;
break;
case 'P3':
statusToReturn = INSTRUCTION_STATUS[4].label;
break;
case 'R3':
statusToReturn = INSTRUCTION_STATUS[5].label;
break;
case 'P4':
statusToReturn = INSTRUCTION_STATUS[6].label;
break;
case 'P5':
statusToReturn = INSTRUCTION_STATUS[7].label;
break;
case 'RB':
statusToReturn = 'ila.receivedByBank';
break;
case 'JB':
statusToReturn = 'ila.rejectedByBank';
break;
case 'JC':
statusToReturn = 'ila.rejectedByCustomer';
break;
case 'RF':
statusToReturn = 'ila.receivedFwdInstr';
break;
default:
statusToReturn = t(`ila.instructionStatus_${status}`) ? `ila.instructionStatus_${status}` : '';
break;
}
return t(statusToReturn);
};
const mapInstructionTypeStoreData = type => {
switch (type) {
case 'C0':
case 'C1':
case 'PP':
return 'ila.pp';
case 'CS':
case 'COS':
return 'ila.cos';
case 'AP':
case 'ACH':
case 'APC':
return 'ila.achCredit';
case 'AD':
case 'APD':
return 'ila.achDebit';
default:
return type;
}
};
const tableDoc = {
pageOrientation: 'landscape',
pageMargins: [25, 74, 25, 60],
footer: (currentPage, pageCount) => PDFFooter(pageName, pageCount, currentPage),
header: () => PDFHeader(fontMargin(fontLocale), pageName),
content: [
{
text: [{ text: messageTitle, bold: true, color: 'black' }, { text: messageBody }, '\n', { text: pdfNote }],
style: 'note'
},
{
style: 'tableStyle',
table: {
headerRows: 1,
dontBreakRows: true,
body: [arrOfHeader, ...getTableRows()],
widths:
arrOfHeader.length === 9
? ['13.3%', '11.3%', '11.3%', '13.3%', '12.3%', '9.1%', '9.1%', '8.6%', '11.6%']
: ['12.8%', '12.8%', '14.8%', '13.8%', '10.6%', '10.6%', '11.4%', '13.1%']
},
layout: {
vLineWidth: () => 1.2,
hLineWidth: hLineIndex => (hLineIndex === 1 ? 0 : 1.2),
hLineColor: () => '#E4E8EA',
// eslint-disable-next-line no-confusing-arrow
vLineColor: (i, node, rowIndex) =>
rowIndex === 0 || (i === 0 || i === arrOfHeader.length) ? 'white' : '#E4E8EA',
fillColor: rowIndex => (rowIndex === 0 ? '#E4E8EA' : null)
}
}
],
styles: {
tableStyle: {
margin: [0, fontMargin(fontLocale), 0, 20]
},
tableHeader: {
bold: true,
color: 'black',
margin: [5, fontMargin(fontLocale), 5, 5]
},
note: {
lineHeight: 2,
italics: false
}
},
defaultStyle: {
columnGap: 10,
font: fontLocale,
color: '#333333',
fontSize: 8
}
};
return tableDoc;
}
export default TablePDF;
const date = new Date();
const gmtString = date.toGMTString();
const finalDate =
JSON.stringify(gmtString).slice(6, 17) +
',' +
JSON.stringify(gmtString).slice(17, 23) +
JSON.stringify(gmtString).slice(26, 30);
const PDF_Footer = (pageName, totalPages, pageNumber, reference) => ({
margin: [30, 20, 30, 10],
stack: [
{
table: {
headerRows: 1,
widths: ['*'],
body: [[''], ['']]
},
layout: {
hLineWidth: i => (i === 0 ? 1 : 0),
vLineWidth: () => 0,
hLineColor: () => 'black'
}
},
{
columns: [
finalDate + ' | ' + pageName + (reference || ''),
{
text: pageNumber && totalPages && `Page ${pageNumber} of ${totalPages}`,
alignment: 'right'
}
]
}
],
color: '#333333',
bold: false
});
export default PDF_Footer;
export function getLanguageFont(text) {
const universal = /^[a-zA-Z0-9_\-/.!@#$%^&*' 'wığüşöçĞÜŞÖÇİÀ-ÿ/]+$/;
const arabic = /[\u0600-\u06FF]/;
const hebrew = /[\u0590-\u05FF]/;
const greek = /[\u0370-\u03ff\u1f00-\u1fff]/;
const japanese = /[\u3000-\u303f\u3040-\u309f\u30a0-\u30ff\uff00-\uff9f\u4e00-\u9faf\u3400-\u4dbf]/;
const korean = /[\u3130-\u318F\uAC00-\uD7AF]/g;
const russian = /[\u0401\u0451\u0410-\u044f]/;
const vietnamese = /^[a-zA-ZÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂẾưăạảấầẩẫậắằẳẵặẹẻẽềềểếỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵỷỹ\s\W|_]+$/;
const chinese = /[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uff66-\uff9f]/;
if (universal.test(text)) {
return 'UniverseNextHSBC';
} else if (arabic.test(text)) {
return 'arabicFont';
} else if (hebrew.test(text)) {
return 'hebrewFont';
} else if (greek.test(text)) {
return 'hebrewFont';
} else if (japanese.test(text)) {
return 'chineseSimple';
} else if (korean.test(text)) {
return 'korean';
} else if (vietnamese.test(text)) {
return 'vietnamese';
} else if (chinese.test(text)) {
return 'chineseSimple';
}
return 'UniverseNextHSBC';
}
pdfMake.createPdf(tableDoc, null, fontCategories).download(('file.pdf', () => setDownloading(false)));