本文将记录如何从纯前端实现生成带图片的表格的word文件,并下载到本地。
依赖 docx 插件
docx文档地址
github地址
npm install --save docx
这里的用例最终生成文档内容长这样
import {Document,ImageRun,Packer,Paragraph,HeadingLevel,TextRun,SymbolRun,AlignmentType,WidthType,BorderStyle,Table,TableRow,TableCell,convertInchesToTwip,VerticalAlign,TableLayoutType
} from 'docx';
export default memo(() => {
// 生成文档大标题
const createHeading = (text1, text2) => {
return new Paragraph({
alignment: AlignmentType.CENTER,
heading: HeadingLevel.HEADING_1,
children: [
new TextRun({
text: text1,
}),
new TextRun({
text: text2,
break: 1,
}),
],
});
};
// 生成文档正文
const createText = (text, num = 0) => {
return new Paragraph({
heading: HeadingLevel.HEADING_4,
children: [
new TextRun({
text: text,
break: num,
}),
],
});
};
// 生成tablecell标题
const createTablecellTitle = (text, type, len) => {
let obj = {};
if (type == 1) {
obj.alignment = AlignmentType.CENTER;
} else {
obj.indent = { start: 100 };
}
return new Paragraph({
...obj,
heading: HeadingLevel.HEADING_5,
children: [new TextRun({
text: text,
})],
});
};
// 生成tablecell正文
const createTablecellText = (text, type, len) => {
let obj = {};
if (type == 1) {
obj.alignment = AlignmentType.CENTER;
} else {
obj.indent = { start: 100 };
}
return new Paragraph({
...obj,
heading: HeadingLevel.HEADING_6,
children: [new TextRun({
text: text,
})],
});
};
// 生成tablecell图片
const createTablecellImg = (photo, width, height, type = 0) => {
let obj = {};
if (type == 0) {
obj.spacing = {
before: 180,
};
}
return new Paragraph({
...obj,
alignment: AlignmentType.CENTER,
children: [
new ImageRun({
data: photo,
transformation: {
width,
height,
},
}),
],
});
};
// 生成纯文字tablecell colspan代表行合并数,type=0表示是标题,1是正文,,needCenter 1需要居中,2是需要自己打断换行的 len是
const createTablecell = (text, colspan = 2, type = 0, needCenter = 0, len = 12) => {
return new TableCell({
verticalAlign: VerticalAlign.CENTER,
columnSpan: colspan,
children: [
type == 0
? createTablecellTitle(text, needCenter, len)
: createTablecellText(text, needCenter, len),
],
});
};
// 生成空行(带border)
const ceateTableRow = () => {
return [
new TableRow({
children: [
new TableCell({
columnSpan: 12,
children: [],
}),
],
}),
];
};
// 将大数组切割成固定长度的小数组,长度不够就填充空对象
const chunk = (arr, size) => {
var arr2 = [];
for (var i = 0; i < arr.length; i = i + size) {
if (arr.slice(i, i + size).length < size) {
let arr3 = arr.slice(i, i + size);
for (var j = 0; j < size; j++) {
if (!arr3[j]) {
arr3[j] = {};
}
}
arr2.push(arr3);
} else {
arr2.push(arr.slice(i, i + size));
}
}
return arr2;
};
/**
* 导出秩序册word
* @param {string} fileName 文件名,不含后缀
*/
const exportWord = async (fileName = 'word') => {
// 数据
let data = [
{
team_name: "xxx", //代表队伍名称
logo: "https://img.zcool.cn/community/011d2b599e435da801201794bfc968.jpg", //队伍LOGO
team_photo:
"https://img.zcool.cn/community/011d2b599e435da801201794bfc968.jpg", //队伍合照
representative: "xxx单位", //参赛单位名称
lead_name: ["姓名1", "姓名2"], //领队
lead_name: ["姓名1"], //教练
contacts_phone: "xxx", //教练
retinues: [
{
role_name: "领队",
name: "姓名1",
photo:
"https://img2.baidu.com/it/u=687610989,4177511047&fm=253&fmt=auto&app=138&f=PNG?w=500&h=527",
phone: "13xxxxx111",
},
{
role_name: "教练",
name: "姓名2",
photo:
"https://img2.baidu.com/it/u=687610989,4177511047&fm=253&fmt=auto&app=138&f=PNG?w=500&h=527",
phone: "130xxxxx110",
},
], //随行人员 每行4个,自动换行
},
];
// word文档共用设置
let commSetting = {
creator: "22", //作者
styles: {
paragraphStyles: [
// 文档大标题
{
id: "Heading1",
name: "Heading 1",
basedOn: "Normal",
next: "Normal",
quickFormat: true,
run: {
size: 32,
bold: true,
color: "000000",
},
paragraph: {
spacing: {
before: 250,
after: 250,
},
},
},
// 文档正文
{
id: "Heading4",
name: "Heading 4",
basedOn: "Normal",
next: "Normal",
quickFormat: true,
run: {
size: 28,
color: "000000",
},
paragraph: {
spacing: {
before: 250,
after: 250,
},
},
},
// 表格正文标题
{
id: "Heading5",
name: "Heading 5",
basedOn: "Normal",
next: "Normal",
quickFormat: true,
run: {
size: 18,
color: "000000",
bold: true,
},
paragraph: {
spacing: {
before: 250,
after: 250,
},
},
},
// 表格正文
{
id: "Heading6",
name: "Heading 6",
basedOn: "Normal",
next: "Normal",
quickFormat: true,
run: {
size: 18,
color: "000000",
},
paragraph: {
spacing: {
before: 180,
after: 180,
},
},
},
],
},
};
let document = null;
// 假设表格有12列
let colums = [];
for (let i = 0; i < 12; i++) {
colums.push(convertInchesToTwip(0.5225));
}
// 统一处理数据 将图片转换成word插件可以执行的格式
for (let item of data) {
item.logo = await fetch(item.logo).then((r) => r.blob());
item.team_photo = await fetch(item.team_photo).then((r) => r.blob());
for (let its of item.retinues) {
const blob = await fetch(its.photo).then((r) => r.blob());
its.photo = blob;
}
}
document = new Document({
...commSetting,
sections: [
{
children: [
createHeading("这是一个假标题", "竞赛报名表"),
...data.map((item, index) => {
let table = null;
const tableCommSetting = {
columnWidths: colums,
layout: TableLayoutType.FIXED, //布局 TableLayoutType有两个属性,一个是FIXED 一个是AUTOFIT
width: {
size: convertInchesToTwip(6.27),
type: WidthType.DXA,
},
};
let retinueARR = [], //随行人员表格内容
retinueArrOfArrays = [];
// 生成"随行人员"图表
if (item?.retinues?.length > 0) {
retinueArrOfArrays = chunk(item.retinues, 4); //随行人员 每行4个,自动换行
retinueARR = retinueArrOfArrays.map((itt, idx) => {
return new TableRow({
children: itt.map((it, ix) => {
if (JSON.stringify(it) == "{}") {
return new TableCell({ columnSpan: 3, children: [] });
} else {
return new TableCell({
columnSpan: 3,
width: {
size: convertInchesToTwip(0.5225 * 3),
type: WidthType.DXA,
},
children: [
createTablecellImg(it.photo, 90, 126),
createTablecellText(it.role_name, 1),
createTablecellText(it.name, 1),
createTablecellText(it.phone, 1),
],
});
}
}),
});
});
} else {
retinueARR = ceateTableRow();
}
table = new Table({
...tableCommSetting,
rows: [
new TableRow({
children: [
createTablecell("代表队伍名称", 2, 0, 2),
createTablecell(item.team_name, 4, 1, 2, 16),
createTablecell("参赛单位名称", 2, 0, 2),
createTablecell(item.representative, 4, 1, 2, 16),
],
}),
new TableRow({
children: [
createTablecell("队伍LOGO", 2, 0, 2),
new TableCell({
verticalAlign: VerticalAlign.CENTER,
columnSpan: 4,
children: [createTablecellImg(item.logo, 126, 40, 1)],
}),
createTablecell("队伍合照", 2, 0, 2),
new TableCell({
verticalAlign: VerticalAlign.CENTER,
columnSpan: 4,
children: [createTablecellImg(item.team_photo, 126, 60, 1)],
}),
],
}),
new TableRow({
children: [
createTablecell("领队", 2, 0, 2),
createTablecell(item.lead_name.join("、"), 2, 1, 2),
createTablecell("教练", 2, 0, 2),
createTablecell(item.coach_name.join("、"), 2, 1, 2),
createTablecell("团队联系方式", 2, 0, 2),
createTablecell(item.contacts_phone, 2, 1, 2, 11),
],
}),
new TableRow({
columnSpan: 12,
children: [createTablecell("随行人员信息", 12, 0, 1)],
}),
...retinueARR,
// 最后一行空白行
ceateTableRowBorderNone(),
],
});
return table;
}),
],
},
],
});
Packer.toBlob(document).then((blob) => {
saveAs(blob, fileName + ".docx");
});
};
return (
<button onClick={() => exportWord('报名表')} > 导出word文档 </button>
)
})
如有不满足需求的地方,还是可以上它的官方文档看看,地址再贴一次文章来源:https://www.toymoban.com/news/detail-598803.html
希望对大家有所帮助,毕竟我肝文档肝了一天,希望给大家节约一点时间文章来源地址https://www.toymoban.com/news/detail-598803.html
到了这里,关于【实战分享】js生成word(docx)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!