导出
导出分为两种方式
- 通过服务方式进行导出
- 通过编写新页面的方式导出
新页面的方式导出
- 新页面的方式进行导出文件,可以导出的文件类型有:xlsx、pdf、docx
- 导出文件中的数据必须在
服务端
进行渲染 - 文件中的本地资源(css、images)需要添加
inline
属性 - 导出文件的页面服务端暂
不能
添加用户权限验证
导出xlsx
- 新页面导出excel只能导出简单内容的数据或者模板
- 导出excel必须使用标签
table
- 本地测试导出excel
http://127.0.0.1:8889/@page-name@.xlsx
导出pdf
- 若展示的pdf内容有滚动条,则可以在页面
n.ts
中body
上设置样式overflow: visible;
- 本地测试导出pdf
http://127.0.0.1:8889/@page-name@.pdf
导出docx
- 若在docx中展示内容为表格形式,请使用
table
标签 - 本地测试导出pdf
http://127.0.0.1:8889/@page-name@.docx
- 在window上测试导出docx
服务导出
- 在服务中可导出的文件类型有:excel、docx、zip
导出excel
- 使用的第三方库
exceljs
[https://github.com/guyonroche/exceljs#readme] - 可以设置文档基本信息
- 可以添加多个页签数据
- 可以设置级联选择
- 可以设置数据验证
导出excel基本方法
- 引入第三方库和基本原子操作
import { Workbook } from 'exceljs'; import { ICommonParams } from '@feidao/service/interfaces'; import zip from '@feidao/web/atom/nodejs/zip/zip';
- 服务函数的定义和参数
export default async function atom(msg: ICommonParams, action_id: string, session_id: string, spaceid: string) { // 在服务中接收地址栏中传入的参数 // 接收参数,http://127.0.0.1:8889/@download@?id=id&spaceid=spaceid const query = msg.query; const _id = query.id; const _spaceid = query.spaceid; }
- 首先创建一个示例 ```ts // 创建一个实例 const wb = new Workbook();
// 可以添加文件描述 wb.creator = ‘feidao’; // creator: string; // 创建者 // lastModifiedBy: string; // 最后修改人 // created: Date; // 创建时间 // modified: Date; // 修改时间 // lastPrinted: Date; // 最后打印时间 // Set workbook dates to 1904 date system // wb.properties.date1904 = true; // wb.views = [ // { // x: 0, y: 0, width: 10000, height: 20000, // firstSheet: 0, activeTab: 1, visibility: ‘visible’ // } // ]
- 在excel中添加数据,第一步创建页签
```ts
// 添加一个页签,可以添加多个页签
// 不输入名称则使用默认名称,可以针对该页签添加属性
// options = {properties:{}, pageSetup:{}, views:[{}]}
const dict1 = wb.addWorksheet();// 该页签的默认名称为`sheet1`
// 可以传入页签名称,符合变量的定义并且不能是excel的关键字
- 导出简单内容(数据标题和数据)
// 在页签dict1中添加表头,表头一定在第一行(如果其他内容在第一行,添加的表头也在第一行) // header 显示内容 // key 关键字 // outlineLevel 设置折叠层级 // numFmt 数据格式 numFmt = '0.00%'; numFmt: 'dd/mm/yyyy' numFmt = '"£"#,##0.00;[Red]\-"£"#,##0.00'; numFmt = '# ?/?'; dict1.columns = [ { header: '教学班编号' }, { header: '教学班名称', key: 'teaching_class', width: 20, outlineLevel: 1 },// B { header: '学号', key: 'student_id', width: 20, outlineLevel: 2, hidden: true },// C { header: '姓名', key: 'student_name', width: 20, outlineLevel: 1 },// D { header: '平时成绩1', key: 'ordinary_performance1', width: 20, style: { numFmt: '0.00%' } },// E { header: '省', key: 'ordinary_performance2', width: 20, style: { font: { // name: '宋体', // 字体名称 // size: 15, // 字体大小 // family: 1, // 1 - Serif, 2 - Sans Serif, 3 - Mono, Others - unknown // scheme: 'minor', charset: 1, // 字符集 1, 2, etc. // color: { argb: 'FFFF00', theme: 0 }, // 字体颜色 // bold: true, // 加粗 // italic: true, // 斜体 // underline: 'doubleAccounting', // 下划线 // strike: true // 删除线 outline: true } } },// F { header: '市', key: 'ordinary_performance3', width: 20, style: { alignment: { // horizontal: 'left', // 水平距左 // vertical: 'justify', // 垂直 justify:两端对齐 // wrapText: true, // 自动换行 // indent: 20, // 缩进 // readingOrder: 'ltr' // textRotation: 'vertical' // 文本回转 } } }, { header: '区', key: 'ordinary_performance4', width: 20, style: { border: { // top: { // style: 'mediumDashDot', // color: { // argb: '#fff' // } // }, // left: { // style: 'thin', // color: { // argb: '#fff' // } // }, // bottom: { // style: 'dotted', // color: { // argb: '#fff' // } // }, // right: { // style: 'medium', // color: { // argb: '#fff' // } // }, diagonal: { up: true, down: true } } } }, { header: '平时成绩5', key: 'ordinary_performance5', width: 20, style: { fill: { // type: 'pattern', // 填充内容,pattern 图案 // pattern: 'darkDown', // 图案形状 // bgColor: { // argb: '008844' // }, // fgColor: { // argb: 'FFB7DD' // 图案颜色 // } type: 'gradient', // 渐变 // gradient: 'angle', // // degree: 90, // 90:垂直,0:水平,45:斜上,135:斜下, gradient: 'path', // 辐射 center: { left: 0.5, top: 0.5 }, // left=top=0.5 中心辐射,其他值为角度辐射 stops: [{ position: 0, color: { argb: 'BB5500' } }, { position: 1, color: { argb: '003377' } }] // position:0和1, } } } ];
- 在页签中添加行数据
// 添加多行数据 dict1.addRows([{ teaching_class_no: '测试001', teaching_class: '测试001', student_id: '测试001', student_name: '测试001', ordinary_performance1: '测试001', ordinary_performance2: '测试001', ordinary_performance3: '测试001', ordinary_performance4: '测试001', ordinary_performance5: '测试001' }]); // 添加一行数据 dict1.addRow({ teaching_class_no: '测试002', teaching_class: '测试002', student_id: '测试002', student_name: '测试002', ordinary_performance1: '测试002', ordinary_performance2: '测试002', ordinary_performance3: '测试002', ordinary_performance4: '测试002', ordinary_performance5: '测试002' });
- 根据展示内容可以将单元格进行合并
// 将单元格进行合并 dict1.mergeCells('B1:C1'); dict1.mergeCells('B2:B6'); dict1.mergeCells('D1:F3'); // 参数为要合并单元格起始位置和结束位置,单元格行和列数是从1开始;同一个单元格不能合并多次,并且被合并的单元格内容将不存在
- 页签基本设置
const dict2 = wb.addWorksheet('学生信息'); // 设置页签的背景颜色 dict2.properties.tabColor = { argb: 'A42D00' }; // 版式,横版 dict2.pageSetup.orientation = 'landscape'; // 纸张 A4 dict2.pageSetup.paperSize = 9; // 打印区域 dict2.pageSetup.printArea = 'A1:G20'; // 打印头部信息,每页显示的头部信息 dict2.pageSetup.printTitlesRow = '1:2';
- 行列基本设置 ```ts // 获取一列 const columns = dict1.getColumn(4); // 设置布局 columns.alignment = {}; // 参考表头基本设置 // 设置字体 columns.font = {}; // 参考表头基本设置 // 设置样式 columns.style = {}; // 参考表头基本设置 // 设置宽度 columns.width = 200; // 设置边框 columns.border = {}; // 参考表头基本设置
// 获取一行 const rows = dict1.getRow(3); // 设置布局 rows.alignment = {}; // 参考表头基本设置 // 设置字体 rows.font = {}; // 参考表头基本设置 // 设置样式 rows.style = {}; // 参考表头基本设置 // 设置高度 rows.height = 200; // 获取某一个单元格 rows.getCell(3);
- 单元格基本设置
```ts
// 获取某一个单元格
const cel = dict1.getCell('Z1');
// 获取一行,可以循环行单元格
const rows = dict1.getRow(3);
// 获取一列,可以循环列单元格
const columns = dict1.getColumn(4);
// 可以设置单元格信息
// 循环每一个单元格
columns.eachCell((cell, rowNumber) => {
if (rowNumber > 1) {
// 回调函数中参数说明,cell为单元格对象,rowNumber即当前单元格所在的行从1开始,不包含第一行
// 设置单元格内容布局
cell.alignment = {
// horizontal: 'left', // 水平距左
// vertical: 'justify', // 垂直 justify:两端对齐
// wrapText: true, // 自动换行
// indent: 20, // 缩进
// readingOrder: 'ltr'
// textRotation: 'vertical' // 文本回转
};
cell.font = {};// 参考表头基本设置
cell.style = {};// 参考表头基本设置
}
});
- 单元格数据验证–序列
// 设置序列的内容为固定值 // 设置单元格验证信息,验证信息为序列,设置单元格内容为下拉框,下拉内容为`男,女` const dict1 = wb.addWorksheet('单元格数据验证'); const cell = dict1.getCell('A1'); cell.dataValidation = { type: 'list', formulae: [`"男,女"`] };
- 单元格设置数据验证参数说明
// cell.dataValidation = { // type: 'textLength', // 数据验证类型 // formulae: [20], // 值 // allowBlank: false, // 忽略空值 // operator: 'lessThan', // 比较类型,小于 // prompt: '提示内容', // 提示信息内容 // promptTitle: '提示标题', // 提示信息标题 // showInputMessage: true, // 显示提示信息 // error: '错误信息', // 错误信息内容 // errorTitle: '错误标题', // 错误信息标题 // showErrorMessage: true, // 显示错误提示信息 // errorStyle: 'information' // 错误信息图标样式,error 错误,warning 警告,information 信息 // };
- 单元格数据验证–序列
// 设置序列的内容来源于数据库或者其他页签 const dict1 = wb.addWorksheet('单元格数据验证'); const cell = dict1.getCell('A1'); // 数据验证formulae说明:学生信息--页签名称,$A$3:$A$5--设置为序列值的区域 cell.dataValidation = { type: 'list', formulae: [`=学生信息!$A$3:$A$5`] };
- 单元格数据验证–序列(根据选择的内容将编号带回)
// 设置序列的内容来源于数据库或者其他页签 const dict1 = wb.addWorksheet('单元格数据验证'); // 设置为选择序列的单元格 const cell = dict1.getCell('A1'); // 数据验证formulae说明:学生信息-页签名称,$A$3:$A$5--设置为序列值的区域 cell.dataValidation = { type: 'list', formulae: [`=学生信息!$A$3:$A$5`] }; // 根据单元格A1选择的内容将对应的编号在A2中显示 const cell2 = dict1.getCell('A2'); // VLOOKUP公式说明,`A1`依据的单元格,`学生信息!$A$3:学生信息!$B$5`筛选的范围,即某一个页签中的数据范围,依据单元格的内容须在筛选范围最左侧,`2`依据筛选内容返回的数据所在筛选范围内的列数(从1开始),`0`精确匹配 cell.value = { formula: `=VLOOKUP($A1,学生信息!$A$3:学生信息!$B$5,2,0)`, result: '' };
- 单元格数据验证–唯一性
// 可以对输入的内容进行唯一性验证 for (let idx = 1; idx < 5000; idx++) { const element = dict1.getCell(`A${idx}`); // 第一列输入的内容唯一性验证 element.dataValidation = { type: 'custom', formulae: [`=countif(A1:A5000,A${idx})=1`], showErrorMessage: true }; } // 获取某一列单元格的两种方式 // 1、获取某一列,然后循环列中的单元格 // 2、直接获取特定的单元格 // 这两种方式的区别为:获取列中的单元格只能获取到已有数据的单元格,未添加数据的单元格是获取不到的
- 单元格数据验证–数值
// 单元格中要求输入 2 -- 10 之间的整数,并显示错误信息 cell.dataValidation = { type: 'whole', // 整数 formulae: [2, 10], // 值区间 operator: 'between',// 区间 showErrorMessage: true }; // 输入的字符串内容长度小于20,并设置了提示信息和错误信息 cell.dataValidation = { type: 'textLength', // 数据验证类型 formulae: [20], // 值 allowBlank: false, // 忽略空值 operator: 'lessThan', // 比较类型,小于 prompt: '提示内容', // 提示信息内容 promptTitle: '提示标题', // 提示信息标题 showInputMessage: true, // 显示提示信息 error: '错误信息', // 错误信息内容 errorTitle: '错误标题', // 错误信息标题 showErrorMessage: true, // 显示错误提示信息 errorStyle: 'information' // 错误信息图标样式,error 错误,warning 警告,information 信息 }; // type还有其他值,请看定义文件
- 单元格设置省市区级联 ```ts // 首先将省,市,区的数据分别渲染到三个页签中,并且在市和区的单元格上添加名称管理器,名称管理器的关键字则为上一级内容 ////////////////////////// 将省市区数据添加到不同页签中 /////////////////////////////////// // 例如数据库存储的数据格式为[{id:’‘,name:’’, pid:’’}] const cascade_data = [{ id: ‘001’, name: ‘河南省’, pid: ‘’ }, { id: ‘002’, name: ‘河北省’, pid: ‘’ }, { id: ‘003’, name: ‘山东省’, pid: ‘’ }, { id: ‘0011’, name: ‘郑州市’, pid: ‘001’ }, { id: ‘0012’, name: ‘濮阳市’, pid: ‘001’ }, { id: ‘00111’, name: ‘金水区’, pid: ‘0011’ }, { id: ‘00112’, name: ‘中原区’, pid: ‘0011’ }, { id: ‘00121’, name: ‘南乐县’, pid: ‘0012’ }, { id: ‘00122’, name: ‘清丰县’, pid: ‘0012’ }, { id: ‘0031’, name: ‘聊城市’, pid: ‘003’ }, { id: ‘0032’, name: ‘济南市’, pid: ‘003’ }, { id: ‘00311’, name: ‘高唐县’, pid: ‘0031’ }, { id: ‘00312’, name: ‘阳谷县’, pid: ‘0031’ }, { id: ‘00321’, name: ‘天桥区’, pid: ‘0032’ }, { id: ‘0021’, name: ‘石家庄市’, pid: ‘002’ }, { id: ‘0022’, name: ‘唐山市’, pid: ‘002’ }, { id: ‘00211’, name: ‘长安区’, pid: ‘0021’ }, { id: ‘00212’, name: ‘新华区’, pid: ‘0021’ }, { id: ‘00221’, name: ‘路北区’, pid: ‘0022’ }, { id: ‘00222’, name: ‘路南区’, pid: ‘0022’ }];
// 省数据,数据处理后的结构符合单元格渲染数据结构,此数据结构为[[‘河南省’],[‘河北省’],[‘山东省’]] const pro_data = cascade_data.filter((item) => { return item.pid === ‘’; }).reduce((pre, cur, idx, array) => { const name = cur.name; pre.push([name]); return pre; }, []);
const dict3 = wb.addWorksheet(‘省’); dict3.addRows(pro_data);
// 市数据,数据处理后的结构符合单元格渲染数据结构,并且在渲染的市数据单元格上添加名称管理器,名称管理器的值则为市的名称,此数据结构为[[‘河南省’,[‘郑州市’,’濮阳市’]],[‘河北省’,[‘石家庄市’,’唐山市’]],[‘山东省’,[‘济南市’,’聊城市’]] const city_data = cascade_data.filter((item) => { return item.pid === ‘’; }).reduce((pre, cur, idx, array) => { const id = cur.id; const name = cur.name; // 获取市数据 const c_data = cascade_data.filter((info) => { return info.pid === id; }).reduce((pre1, cur1, idx1, array1) => { pre1.push(cur1.name); return pre1; }, []); const arr = [name, c_data]; pre.push(arr); return pre; }, []);
const dict4 = wb.addWorksheet(‘市’); city_data.forEach((item, idx) => { const name = item[0]; const data = item[1]; dict4.addRow(data); // 获取刚渲染的行 const r = dict4.getRow(idx + 1); // 获取每一个单元格,在单元格上添加名称管理器 r.eachCell((cell, colNumber) => { // 设置单元格名称管理器 cell.addName(name); }); });
// 区数据,数据机构和市数据结构一致并添加名称管理器 const area_data: any[] = []; cascade_data.filter((item) => { return item.pid === ‘’; }).map((pro_item) => { const id = pro_item.id; const c_data = cascade_data.filter((item) => { return item.pid === id; }).map((c_item) => { const cid = c_item.id; const name = c_item.name; const a_data = cascade_data.filter((item) => { return item.pid === cid; }).reduce((pre, cur, idx, array) => { pre.push(cur.name); return pre; }, []); area_data.push([name, a_data]); }); });
const dict5 = wb.addWorksheet(‘区’); area_data.forEach((item, idx) => { const name = item[0]; const data = item[1]; dict5.addRow(data); const r = dict5.getRow(idx + 1); r.eachCell((cell, colNumber) => { // 添加名称管理器,name要以字母或下划线开头,不能包含空格,不能与excel内部或者工作薄中其他对象名称冲突 cell.addName(name); }); }); ////////////////////////// 将省市区数据添加到不同页签中 ///////////////////////////////////
/**
- 开始在第一个页签中设置省,市,区数据来源 */
/**
- 省
*/
for (let idx = 1; idx < 5000; idx++) {
const element = dict1.getCell(
F${idx}
); element.dataValidation = { type: ‘list’, formulae: [=省!$A$1:$A$${pro_data.length + 1}
] }; }
/**
- 市
*/
for (let idx = 1; idx < 5000; idx++) {
const element = dict1.getCell(
G${idx}
); element.dataValidation = { type: ‘list’, formulae: [=INDIRECT(F${idx})
] }; }
/**
- 区
*/
for (let idx = 1; idx < 5000; idx++) {
const element = dict1.getCell(
H${idx}
); element.dataValidation = { type: ‘list’, formulae: [=INDIRECT(G${idx})
] }; } ``` - 导出一个文件
// 获取内容buff const buff = await wb.xlsx.writeBuffer() as Buffer; // 返回数据,键为固定内容,attachment为文件名称 return { buff, content_type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', attachment: '表格下载.xlsx' };
- 一次导出多个文件并压缩
// 获取内容buff const buff = await wb.xlsx.writeBuffer() as Buffer; const res = await zip({ file: buff, path: 'zip/测试.xlsx' }); return { attachment: '压缩包名称.zip', buff: res, content_type: 'application/octet-stream' };
导出docx
- 使用的第三方库为
docx
[https://docx.js.org/#/examples]
导出docx基本方法
- 引入第三方库和基本原子操作
import * as docx from 'docx'; import { ICommonParams } from '@feidao/service/interfaces'; import zip from '@feidao/web/atom/nodejs/zip/zip';
- 导出函数和参数
export default async function atom(msg: ICommonParams, action_id: string, session_id: string, spaceid: string) { // 在服务中接收地址栏中传入的参数 // 接收参数,http://127.0.0.1:8889/@download@?id=id&spaceid=spaceid const query = msg.query; const _id = query.id; const _spaceid = query.spaceid; }
- 创建实例
const doc = new docx.Document();
- 可以设置word的基本属性信息
// 设置文件属性 const opts = { title: 'title', // 标题 subject: 'subject', // 主题 creator: 'creator', // 创建人 keywords: 'keywords', // 标记 description: 'description', // 描述 lastModifiedBy: 'lastModifiedBy' // 最后一次保存者 }; const doc = new docx.Document(opts);
- 可以设置word的页面布局
// 设置文件属性 const opts = { title: 'title', // 标题 subject: 'subject', // 主题 creator: 'creator', // 创建人 keywords: 'keywords', // 标记 description: 'description', // 描述 lastModifiedBy: 'lastModifiedBy' // 最后一次保存者 }; // 设置页面布局 const section_opt = { // width: 10000, // 宽 17.64 厘米 必须介于 0.26和55.87 厘米 之间 // height: 10000 // 高 // orientation: docx.PageOrientation.LANDSCAPE, // 纸张方向 PORTRAIT 横 LANDSCAPE 纵 // top: 3000, // 页边距 上 5.29 厘米 // right: 4000, // 页边距 右 7.05 厘米 // bottom: 3000,// 页边距 下 // left: 2000, // 页边距 坐 3.53 厘米 // header: 500, // 版式 距边界:页眉 0.88 厘米 // footer: 2000 // 版式 距边界:页脚 3.53 厘米 // gutter: 500, // 页边距 装订线 0.88 厘米 // mirror: false // 未知 }; const doc = new docx.Document(opts,section_opt);
- 可以在word中添加正文、标题、页眉、页脚、页签、脚注、表格、段落
- 在word中添加页眉、页脚
// 设置页眉 doc.Header.addParagraph(new docx.Paragraph('header text')); // 设置页脚 doc.Footer.addParagraph(new docx.Paragraph('footer text')); // 可以添加表格、图片、段落
- word中有已设置好的标题、标题1-7
// 设置内容样式为 标题 doc.addParagraph(new docx.Paragraph('标题').title().pageBreakBefore()); // 设置样式 标题1 居中 doc.addParagraph(new docx.Paragraph('标题1').heading1().center()); // 设置样式 标题2 左对齐 doc.addParagraph(new docx.Paragraph('标题2').heading2().left()); // 设置样式 标题3 右对齐 doc.addParagraph(new docx.Paragraph('标题3').heading3().right()); // 设置样式 标题4 两端对齐 doc.addParagraph(new docx.Paragraph('标题4').heading4().justified()); // 设置样式 标题5 添加标题间隔 doc.addParagraph(new docx.Paragraph('标题5').heading5().thematicBreak()); doc.addParagraph(new docx.Paragraph('标题6').heading6());
- 除了使用已有的标题之外也可以自定义样式
///////////////////// 自定义段落样式 ///////////////////////////////// const ps = doc.Styles.createParagraphStyle('sid', 'name'); // ps.allCaps(); // 未知 ps.bold() // 加粗 .center() // 居中 .characterSpacing(30) // 字体 间距 1.5磅 .color('999999') // 字体颜色 .doubleStrike() // 双删除线 .font('Calibri') // 字体 .indent({ right: 30 }) // 缩进 left: 20, 左缩进0.04厘米。 .italics() // 斜体 .justified() // 两端对其 .keepLines() // 段落 换行与分页 段中不分页 .keepNext() // 段落 换行与分页 与下段同页 .leftTabStop(30) .maxRightTabStop() .next('nid') .quickFormat() .size(15) // 字号 6号 .spacing({ after: 30 }); // 段落 间距 段后1.5磅 // 分页 /** * pageBreak 与之后的内容分页 * pageBreakBefore 与之前的内容分页 */ doc.createParagraph("我是设置的自定义段落,我是设置的自定义段落,我是设置的自定义段落,我是设置的自定义段落,我是设置的自定义段落,我是设置的自定义段落").style('sid').pageBreak(); ///////////////////// 自定义段落样式 /////////////////////////////////
- 列出段落
//////////////////////// 列出段落 ///////////////////////////////////////// const abstractNum = new docx.Numbering().createAbstractNumbering(); abstractNum.createLevel(0, "upperRoman", "%1", "start").addParagraphProperty(new docx.Indent({ left: 720, hanging: 260 })); abstractNum.createLevel(1, "decimal", "%2.", "start").addParagraphProperty(new docx.Indent({ left: 720, hanging: 980 })); abstractNum.createLevel(2, "lowerLetter", "%1)", "start").addParagraphProperty(new docx.Indent({ left: 720, hanging: 1700 })); const concrete = new docx.Numbering().createConcreteNumbering(abstractNum); /** * setNumbering 设置为列表 * concrete * 0 列表级别,从0开始到8 */ doc.addParagraph(new docx.Paragraph('numbering1').setNumbering(concrete, 0)); doc.addParagraph(new docx.Paragraph('numbering 2').setNumbering(concrete, 1)); doc.addParagraph(new docx.Paragraph('numbering3').setNumbering(concrete, 2)); //////////////////////// 列出段落 /////////////////////////////////////////
- 分页 ```ts // 分页 /**
- pageBreak 与之后的内容分页
- pageBreakBefore 与之前的内容分页 */ doc.createParagraph(“我是设置的自定义段落,我是设置的自定义段落,我是设置的自定义段落,我是设置的自定义段落,我是设置的自定义段落,我是设置的自定义段落”).style(‘sid’).pageBreak(); doc.createParagraph(“three Page”).pageBreakBefore(); ```
- 脚注 ```ts /////////////////////////// 添加脚注 /////////////////////////////// // 将鼠标放到文本上显示脚注内容 /**
- referenceFootnote 设置脚注编号 */ const paragraph = new docx.Paragraph(“Hello World”).referenceFootnote(1); const paragraph2 = new docx.Paragraph(“Hello World”).referenceFootnote(2);
doc.addParagraph(paragraph); doc.addParagraph(paragraph2);
doc.createFootnote(new docx.Paragraph(“Test”)); doc.createFootnote(new docx.Paragraph(“My amazing reference”)); ///////////////////////////// 添加脚注 /////////////////////////////
- 书签
```ts
// 添加书签
/**
* anchorID 书签名称
* Lorem Ipsum 针对添加书签内容 显示的内容
*/
const bookmark = doc.createBookmark('anchorID', "Lorem Ipsum");
- 项目符号 ```ts /**
- bullet 项目符号 */ const paragraph3 = new docx.Paragraph(‘我是段落’).bullet(); ```
- 正文
//////////////////////////// 正文 ////////////////////////////////////// const text = new docx.TextRun("My awesome text here for my university dissertation"); // 加粗 text.bold(); // 斜体 text.italic(); // 下划线 text.underline(); const text1 = new docx.TextRun('正文哦~~~~~~~~~~~~~~~'); // 删除线 text1.strike(); const text2 = new docx.TextRun('正文哦------------------'); // 双删除线 text2.doubleStrike(); // 下标 text2.subScript(); const text3 = new docx.TextRun('正文哦---------正文哦---------'); // 上标 text3.superScript(); text3.allCaps(); const text4 = new docx.TextRun('正文哦---------正文哦---------正文哦'); text4.smallCaps(); text4.break(); const text5 = new docx.TextRun('----正文哦---------正文哦---------正文哦-----正文哦'); doc.addParagraph(new docx.Paragraph().addRun(text).addRun(text1).addRun(text2).addRun(text3).addRun(text4).addRun(text5)); //////////////////////////// 正文 //////////////////////////////////////
- 表格
//////////////////////////// 表格 ////////////////////////////////////// // 创建table const table = doc.createTable(4, 4); // 表格的行和列是从0开始 // 获取某一个单元格并设置内容 table.getCell(2, 2).addContent(new docx.Paragraph("Hello")); // 设置单元格 table.getCell(2, 2) .CellProperties.Borders.addTopBorder(docx.BorderStyle.DASH_DOT_STROKED, 3, "red") .addBottomBorder(docx.BorderStyle.DOUBLE, 3, "blue") .addStartBorder(docx.BorderStyle.DOT_DOT_DASH, 3, "green") .addEndBorder(docx.BorderStyle.DOT_DOT_DASH, 3, "#ff8000"); // 获取第二行,并将第二个和第三个单元格合并 table.getRow(1).mergeCells(1, 2); table.getCell(0, 0).addContent(new docx.Paragraph('第一个单元格')); table.getCell(0, 0).CellProperties // .setVerticalAlign(docx.VerticalAlign.BOTTOM) // 设置单元格 底部对齐,上,中,下 // .setWidth(200, docx.WidthType.DXA) // 设置单元格宽度 .setShading({ color: 'D8BFD8' }); // 设置表格宽度, PERCENTAGE 百分比 table.setWidth(docx.WidthType.NIL, '16.1cm'); //////////////////////////// 表格 //////////////////////////////////////
- 导出一个word文档
////////////////////// 导出一个docx文档 ////////////////////////// const packer = new docx.Packer(); const res = await (() => { return new Promise<Buffer>((resolve, reject) => { packer.toBuffer(doc).then(async (buffer) => { resolve(buffer); }); }); })(); return { attachment: 'test.docx', buff: res, content_type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }; ////////////////////// 导出一个docx文档 //////////////////////////
- 导出多个word文档并压缩
////////////////////////// 导出压缩包 ///////////////////////////////// const packer = new docx.Packer(); const res = await (() => { return new Promise<Buffer>((resolve, reject) => { packer.toBuffer(doc).then(async (buffer) => { resolve(buffer); }); }); })(); const rt = await zip({ file: Buffer.from(res), path: 'test.docx' }); return { attachment: '压缩包名称.zip', buff: rt, content_type: 'application/octet-stream' }; ////////////////////////// 导出压缩包 /////////////////////////////////