sheetJs / xlsx-js-style 纯前端实现导出 excel 表格及自定义单元格样式 ...

打印 上一主题 下一主题

主题 975|帖子 975|积分 2925


一、安装



  • xlsx 地址:https://www.npmjs.com/package/xlsx
  • SheetJs 地址:https://docs.sheetjs.com/docs/
  • xlsx-js-style 地址:https://www.npmjs.com/package/xlsx-js-style
  1. npm install xlsx-js-style
复制代码
二、创建根本工作表

  1. <script lang="ts" setup>
  2. import { utils, writeFileXLSX } from 'xlsx'
  3. const list = [
  4.     { Name: 'Bill Clinton', Index: 42 },
  5.     { Name: 'GeorgeW Bush', Index: 43 },
  6.     { Name: 'Barack Obama', Index: 44 },
  7.     { Name: 'Donald Trump', Index: 45 },
  8.     { Name: 'Joseph Biden', Index: 46 },
  9. ]
  10. const exportFile = () => {
  11.     // 创建一个工作簿 workbook
  12.     const workBook = utils.book_new()
  13.     // 创建工作表 worksheet
  14.     // json_to_sheet         是将【由对象组成的数组】转化成sheet
  15.     // aoa_to_sheet          是将【一个二维数组】转化成 sheet
  16.     // table_to_sheet          是将【table的dom】直接转成sheet
  17.     // 这里我们使用 json_to_sheet
  18.     const workSheet = utils.json_to_sheet(list)
  19.     // 将工作表放入工作簿中
  20.     // utils.book_append_sheet(workbook, worksheet, name, true);
  21.     utils.book_append_sheet(workBook, workSheet, 'Data')
  22.     // 生成数据保存
  23.     writeFileXLSX(workBook, `SheetJSVueAoO.xlsx`, {
  24.         bookType: 'xlsx',
  25.     })
  26. }
  27. </script>
  28. <template>
  29.     <div>
  30.         <button @click="exportFile">创建工作表</button>
  31.     </div>
  32. </template>
复制代码

三、设置单元格宽度/高度/隐藏单元格



  • !cols 设置列宽
    cols 为一个对象数组,依次表现每一列的宽度
    wpx 字段表现以像素为单元,wch 字段表现以字符为单元
    hidden 如果为真,则隐藏该列
  • !rows 设置行高
    rows 为一个对象数组,依次表现每一行的高度
  1. <script lang="ts" setup>
  2. import { utils, writeFileXLSX } from 'xlsx-js-style'
  3. const list = [
  4.     {
  5.         Name: 'Bill Clinton',
  6.         Date: '2023-01-01',
  7.         'Source category name': 'Excise Taxes',
  8.         'Source subcategory name': 'Corporation Income Taxes',
  9.     },
  10.     {
  11.         Name: 'GeorgeW Bush',
  12.         Date: '2023-01-01',
  13.         'Source category name': 'Excise Taxes',
  14.         'Source subcategory name': 'Corporation Income Taxes',
  15.     },
  16.     {
  17.         Name: 'Barack Obama',
  18.         Date: '2023-01-01',
  19.         'Source category name': 'Excise Taxes',
  20.         'Source subcategory name': 'Corporation Income Taxes',
  21.     },
  22.     {
  23.         Name: 'Donald Trump',
  24.         Date: '2023-01-01',
  25.         'Source category name': 'Excise Taxes',
  26.         'Source subcategory name': 'Corporation Income Taxes',
  27.     },
  28.     {
  29.         Name: 'Joseph Biden',
  30.         Date: '2023-01-01',
  31.         'Source category name': 'Excise Taxes',
  32.         'Source subcategory name': 'Corporation Income Taxes',
  33.     },
  34. ]
  35. const exportFile = () => {
  36.     // 创建一个工作簿 workbook
  37.     const workBook = utils.book_new()
  38.     // 创建工作表 worksheet
  39.     const workSheet = utils.json_to_sheet(list)
  40.     // 设置列宽
  41.     // cols 为一个对象数组,依次表示每一列的宽度
  42.     // wpx 字段表示以像素为单位,wch 字段表示以字符为单位
  43.     // hidden 如果为真,则隐藏该列
  44.     workSheet['!cols'] = [
  45.         { wpx: 100 },
  46.         { wch: 50 },
  47.         { width: 30 },
  48.         { hidden: true },
  49.     ]
  50.     // 设置行高
  51.     // rows 为一个对象数组,依次表示每一行的高度
  52.     workSheet['!rows'] = [{ hpx: 30 }, { hpt: 50 }, { hidden: true }]
  53.     // 将工作表放入工作簿中
  54.     // utils.book_append_sheet(workbook, worksheet, name, true);
  55.     utils.book_append_sheet(workBook, workSheet, 'Data')
  56.     // 生成数据保存
  57.     writeFileXLSX(workBook, `SheetJSVueAoO.xlsx`, {
  58.         bookType: 'xlsx',
  59.     })
  60. }
  61. </script>
  62. <template>
  63.     <div>
  64.         <button @click="exportFile">设置单元格宽度/高度/隐藏</button>
  65.     </div>
  66. </template>
复制代码

四、分配数字格式

  1. <script lang="ts" setup>
  2. import { utils, writeFileXLSX } from 'xlsx-js-style'
  3. const list = [
  4.     { Name: 'Barack Obama', Taxes: 726223 },
  5.     { Name: 'GeorgeW Bush', Taxes: 3.5 },
  6.     { Name: 'Bill Clinton', Taxes: 45571 },
  7.     { Name: 'Donald Trump', Taxes: 0.0219 },
  8.     { Name: 'Donald Trump', Taxes: new Date() },
  9.     { Name: 'Joseph Biden', Taxes: 666666 },
  10. ]
  11. const exportFile = () => {
  12.     // 创建一个工作簿 workbook
  13.     const workBook = utils.book_new()
  14.     // 创建工作表 worksheet
  15.     const workSheet = utils.json_to_sheet(list)
  16.     // 分配数字格式
  17.     workSheet['B3'].z = '"$"#,##0.00_);\\("$"#,##0.00\\)'
  18.     workSheet['B4'].z = '#,##0'
  19.     workSheet['B5'].z = '0.00%'
  20.     workSheet['B6'].z = 'yyyy-mm-dd hh:mm:ss AM/PM'
  21.     workSheet['B7'].z = '[Red](#,##0)'
  22.     // 将工作表放入工作簿中
  23.     // utils.book_append_sheet(workbook, worksheet, name, true);
  24.     utils.book_append_sheet(workBook, workSheet, 'Data')
  25.     // 生成数据保存
  26.     writeFileXLSX(workBook, `SheetJSVueAoO.xlsx`, {
  27.         bookType: 'xlsx',
  28.     })
  29. }
  30. </script>
  31. <template>
  32.     <div>
  33.         <button @click="exportFile">分配数字格式</button>
  34.     </div>
  35. </template>
复制代码

五、超链接

  1. <script lang="ts" setup>
  2. import { utils, writeFileXLSX } from 'xlsx-js-style'
  3. const list = [
  4.     { Name: 'https://sheetjs.com' },
  5.     { Name: '电子邮箱' },
  6.     { Name: '访问 C 盘文件' },
  7.     { Name: '选中指定单元格' },
  8.     { Name: '跳转指定 Sheet' },
  9.     { Name: 'Joseph Biden' },
  10. ]
  11. const exportFile = () => {
  12.     // 创建一个工作簿 workbook
  13.     const workBook = utils.book_new()
  14.     // 创建工作表 worksheet
  15.     const workSheet = utils.json_to_sheet(list)
  16.     // 链接 https://sheetjs.com
  17.     workSheet['A2'].l = {
  18.         Target: 'https://sheetjs.com',
  19.         Tooltip: 'https://sheetjs.com',
  20.     }
  21.     // 链接电子邮箱
  22.     workSheet['A3'].l = { Target: 'mailto:ignored@dev.null' }
  23.     // 访问本地 C 盘文件
  24.     workSheet['A4'].l = { Target: 'file:///C:/Users/pc/Downloads/receipts.xls' }
  25.     // 选中指定单元格 A1:C5
  26.     workSheet['A5'].l = { Target: '#A1:C5', Tooltip: '选中 A1:C5 ' }
  27.     // 跳转指定 Sheet
  28.     workSheet['A6'].l = { Target: '#Data2!A1:C6', Tooltip: 'Data2' }
  29.     workSheet['A7'].l = { Target: '#SheetJSDN', Tooltip: 'Defined Name' }
  30.     // 将工作表放入工作簿中
  31.     // utils.book_append_sheet(workbook, worksheet, name, true);
  32.     utils.book_append_sheet(workBook, workSheet, 'Data')
  33.     // 创建工作表2 worksheet
  34.     var worksheet2 = utils.aoa_to_sheet([['Same', 'Cross', 'Name']])
  35.     utils.book_append_sheet(workBook, worksheet2, 'Data2')
  36.     // 定义的名称, ref 选中的是当前超链接所在单元格位置
  37.     workBook.Workbook = {
  38.         Names: [{ Name: 'SheetJSDN', Ref: 'Data2!A1:A1' }],
  39.     }
  40.     // 生成数据保存
  41.     writeFileXLSX(workBook, `SheetJSVueAoO.xlsx`, {
  42.         bookType: 'xlsx',
  43.     })
  44. }
  45. </script>
  46. <template>
  47.     <div>
  48.         <button @click="exportFile">超链接</button>
  49.     </div>
  50. </template>
复制代码


  • 鼠标移上去看到小手标识及提示语,点击即可看到对应的超链接效果;

六、单元格注释

  1. <script lang="ts" setup>
  2. import { utils, writeFileXLSX } from 'xlsx-js-style'
  3. const list = [{ Name: 'Vue' }, { Name: 'React' }, { Name: 'Angular' }]
  4. const exportFile = () => {
  5.     // 创建一个工作簿 workbook
  6.     const workBook = utils.book_new()
  7.     // 创建工作表 worksheet
  8.     const workSheet = utils.json_to_sheet(list)
  9.     // 添加注释
  10.     if (!workSheet.A2.c) workSheet.A2.c = []
  11.     workSheet.A2.c.push({
  12.         a: 'Vue',
  13.         t: 'Vue 是一款用于构建用户界面的 JavaScript 框架',
  14.     })
  15.     if (!workSheet.A3.c) workSheet.A3.c = []
  16.     // 如果设置为 true,则只有当用户将鼠标悬停在注释上时,注释才可见;
  17.     workSheet.A3.c.hidden = true
  18.     workSheet.A3.c.push({
  19.         a: 'React',
  20.         t: 'React 用于构建 Web 和原生交互界面的库',
  21.     })
  22.     if (!workSheet.A4.c) workSheet.A4.c = []
  23.     // 如果设置为 true,则只有当用户将鼠标悬停在注释上时,注释才可见;
  24.     workSheet.A4.c.hidden = true
  25.     workSheet.A4.c.push({
  26.         a: 'Angular',
  27.         t: 'Angular 是一个应用设计框架与开发平台,旨在创建高效而精致的单页面应用',
  28.     })
  29.     // 将工作表放入工作簿中
  30.     utils.book_append_sheet(workBook, workSheet, 'Data')
  31.     // 生成数据保存
  32.     writeFileXLSX(workBook, `SheetJSVueAoO.xlsx`, {
  33.         bookType: 'xlsx',
  34.     })
  35. }
  36. </script>
  37. <template>
  38.     <div>
  39.         <button @click="exportFile">单元格注释</button>
  40.     </div>
  41. </template>
复制代码

七、公式

  1. <script lang="ts" setup>
  2. import { utils, writeFileXLSX, writeFile } from 'xlsx-js-style'
  3. const list = [
  4.     ['姓名', '语文', '数学', '英语', '总数', '最大值', '姓名去重'],
  5.     ['张三', 80, 100, 100],
  6.     ['李四', 90, 100, 80],
  7.     ['李四', 85, 80, 100],
  8.     ['王五', 100, 85, 90],
  9.     ['张三', 90, 70, 90],
  10.     ['赵六', 95, 90, 80],
  11.     ['张三', 100, 80, 90],
  12. ]
  13. const exportSimpleFormula = () => {
  14.     var ws = utils.aoa_to_sheet([
  15.         [6], // A1
  16.         [8], // A2
  17.         [{ t: 'n', v: 3, f: 'SUM(A1,A2)' }], // SUM 函数
  18.         [{ t: 'n', v: 3, f: 'CONCAT("concat:",A1,A2)' }], // CONCAT 函数
  19.     ])
  20.     var wb = utils.book_new()
  21.     utils.book_append_sheet(wb, ws, 'Sheet1')
  22.     writeFile(wb, 'SheetJSFormula.xlsx')
  23. }
  24. const exportFile = () => {
  25.     // 创建一个工作簿 workbook
  26.     const workBook = utils.book_new()
  27.     // 创建工作表 worksheet
  28.     const workSheet = utils.aoa_to_sheet(list)
  29.     utils.sheet_set_array_formula(workSheet, 'E2:E8', 'B2:B8+C2:C8+D2:D8', true)
  30.     list.forEach((e: (string | number)[], index: number) => {
  31.         if (index > 0) {
  32.             utils.sheet_set_array_formula(
  33.                 workSheet,
  34.                 `F${index + 1}`,
  35.                 `MAX(B${index + 1},C${index + 1},D${index + 1})`,
  36.                 true
  37.             )
  38.         }
  39.     })
  40.     utils.sheet_set_array_formula(
  41.         workSheet,
  42.         'G2:G8',
  43.         '_xlfn.UNIQUE(A2:A8)',
  44.         true
  45.     )
  46.     // 将工作表放入工作簿中
  47.     utils.book_append_sheet(workBook, workSheet, 'Data')
  48.     // 生成数据保存
  49.     writeFileXLSX(workBook, `SheetJSVueAoO.xlsx`, {
  50.         bookType: 'xlsx',
  51.     })
  52. }
  53. </script>
  54. <template>
  55.     <div>
  56.         <button @click="exportSimpleFormula">简单公式</button>
  57.         &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
  58.         <button @click="exportFile">数组公式</button>
  59.     </div>
  60. </template>
复制代码


  • 给单元格增加公式,比如下面:求指定单元格中的最大值(MAX函数);
  • 在 “结果” 双击即可看到对应的公式,按 " ESC" 即可退出;

八、合并单元格



  • !merges 设置单元格合并
  • merges 为一个对象数组,每个对象设定了单元格合并的规则
  • 方法一:通过 decode_range 设置范围合并单元格
  • 方法二:手动设置 A1-C1 的单元格合并(s:开始位置, e:结束位置, r:行, c:列)
  1. <script lang="ts" setup>
  2. import { utils, writeFile } from 'xlsx-js-style'
  3. const exportFile = () => {
  4.     var ws = utils.aoa_to_sheet([
  5.         // 特别注意合并的地方后面预留 2 个 null, 否则后面的内容(本例中是第四列其它信息)会被覆盖
  6.         ['主要信息', null, null, '其它信息'],
  7.         ['姓名', '性别', '年龄', '注册时间'],
  8.         ['张三', '男', 18, new Date()],
  9.         ['李四', '女', 22, new Date()],
  10.     ])
  11.     if (!ws['!merges']) ws['!merges'] = []
  12.     // 方法一:通过 decode_range 设置范围合并单元格
  13.     ws['!merges'].push(utils.decode_range('A1:C1'))
  14.     // 方法二:手动设置 A1-C1 的单元格合并
  15.     // merges 为一个对象数组,每个对象设定了单元格合并的规则
  16.     // s:开始位置, e:结束位置, r:行, c:列
  17.     // ws['!merges'] = [
  18.     //     { s: { r: 0, c: 0 }, e: { r: 0, c: 2 } },
  19.     // ]
  20.     var wb = utils.book_new()
  21.     utils.book_append_sheet(wb, ws, 'Sheet1')
  22.     writeFile(wb, 'SheetJSVueAoO.xlsx')
  23. }
  24. </script>
  25. <template>
  26.     <div>
  27.         <button @click="exportFile">合并单元格</button>
  28.     </div>
  29. </template>
复制代码

九、自定义单元格样式

  1. <script lang="ts" setup>
  2. import { utils, writeFile } from 'xlsx-js-style'
  3. const header = [
  4.     [[]], // 占位
  5.     [
  6.         {}, // 占位
  7.         {
  8.             v: `工厂统计表 ${'\n'}`,
  9.             t: 's',
  10.             s: {
  11.                 font: {
  12.                     sz: 15, //设置标题的字号
  13.                     bold: true, //设置标题是否加粗
  14.                     name: '宋体',
  15.                 },
  16.                 //设置标题水平竖直方向居中,并自动换行展示
  17.                 alignment: {
  18.                     horizontal: 'center',
  19.                     vertical: 'center',
  20.                     wrapText: true,
  21.                 },
  22.                 fill: {
  23.                     fgColor: { rgb: '9FE3FF' },
  24.                 },
  25.             },
  26.         },
  27.     ],
  28. ]
  29. const info = [
  30.     [
  31.         null,
  32.         {
  33.             v: '                                                                                                                                                                                                                                                                                                                                                                                                    统计时间:2023/01/01 00:00',
  34.             t: 's',
  35.             s: {
  36.                 fill: {
  37.                     fgColor: { rgb: '9FE3FF' },
  38.                 },
  39.             },
  40.         },
  41.     ],
  42.     [
  43.         null,
  44.         {
  45.             v: '                                                                                                                                                                                                                                                                                                                                                                                                    统计维度:按月',
  46.             t: 's',
  47.             s: {
  48.                 fill: {
  49.                     fgColor: { rgb: '9FE3FF' },
  50.                 },
  51.             },
  52.         },
  53.     ],
  54.     [
  55.         null,
  56.         {
  57.             v: '                                                                                                                                                                                                                                                                                                                                                                                                    统计周期:2023/01/01 至 2023/01/01',
  58.             t: 's',
  59.             s: {
  60.                 alignment: {
  61.                     vertical: 'top',
  62.                 },
  63.                 fill: {
  64.                     fgColor: { rgb: '9FE3FF' },
  65.                 },
  66.             },
  67.         },
  68.     ],
  69. ]
  70. const risk = [
  71.     '序号',
  72.     '险别',
  73.     '企财险',
  74.     '家财险',
  75.     '机动车',
  76.     '责任险',
  77.     '意外险',
  78.     '货运险',
  79.     '保证险',
  80.     '其他险',
  81. ]
  82. const data = risk.map((e) => {
  83.     return {
  84.         v: e,
  85.         t: 's',
  86.         s: {
  87.             font: {
  88.                 bold: true, //设置标题是否加粗
  89.                 name: '宋体',
  90.             },
  91.             //设置标题水平竖直方向居中,并自动换行展示
  92.             alignment: {
  93.                 horizontal: 'center',
  94.                 vertical: 'center',
  95.                 wrapText: true,
  96.             },
  97.             border: {
  98.                 top: { style: 'thin', color: { rgb: '000000' } },
  99.                 bottom: { style: 'thin', color: { rgb: '000000' } },
  100.                 left: { style: 'thin', color: { rgb: '000000' } },
  101.                 right: { style: 'thin', color: { rgb: '000000' } },
  102.             },
  103.             fill: {
  104.                 fgColor: { rgb: '9FE3FF' },
  105.             },
  106.         },
  107.     }
  108. })
  109. const random = (min: number, max: number): number => {
  110.     return Math.floor(Math.random() * (max - min)) + min
  111. }
  112. const dataArr = () => {
  113.     const items: (Object | null)[][] = []
  114.     Array.apply(null, { length: 18 } as any).map((e, index: number) => {
  115.         const item: (Object | null)[] = [null]
  116.         Array.apply(null, { length: 10 } as any).map((ele, idx: number) => {
  117.             item.push({
  118.                 v: idx === 0 ? index + 1 : random(1, 100000),
  119.                 t: 's',
  120.                 s: {
  121.                     font: {
  122.                         name: '宋体',
  123.                     },
  124.                     alignment: {
  125.                         horizontal: 'center',
  126.                         vertical: 'center',
  127.                     },
  128.                     border: {
  129.                         top: { style: 'thin', color: { rgb: '000000' } },
  130.                         bottom: { style: 'thin', color: { rgb: '000000' } },
  131.                         left: { style: 'thin', color: { rgb: '000000' } },
  132.                         right: { style: 'thin', color: { rgb: '000000' } },
  133.                     },
  134.                 },
  135.             })
  136.         })
  137.         items.push(item)
  138.     })
  139.     return items
  140. }
  141. const exportFile = () => {
  142.     var ws = utils.aoa_to_sheet([
  143.         ...header,
  144.         ...info,
  145.         [null, ...data],
  146.         ...dataArr(),
  147.     ])
  148.     // 合并单元格
  149.     if (!ws['!merges']) ws['!merges'] = []
  150.     ws['!merges'].push(utils.decode_range('B2:K2'))
  151.     ws['!merges'].push(utils.decode_range('B3:K3'))
  152.     ws['!merges'].push(utils.decode_range('B4:K4'))
  153.     ws['!merges'].push(utils.decode_range('B5:K5'))
  154.     ws['!merges'].push(utils.decode_range('A2:A5'))
  155.     ws['!merges'].push(utils.decode_range('L2:L5'))
  156.     // 设置列宽
  157.     // cols 为一个对象数组,依次表示每一列的宽度
  158.     if (!ws['!cols']) ws['!cols'] = []
  159.     ws['!cols'] = [
  160.         { wpx: 70 },
  161.         { wpx: 118 },
  162.         { wpx: 118 },
  163.         { wpx: 118 },
  164.         { wpx: 118 },
  165.         { wpx: 118 },
  166.         { wpx: 118 },
  167.         { wpx: 118 },
  168.         { wpx: 118 },
  169.         { wpx: 118 },
  170.         { wpx: 200 },
  171.     ]
  172.     // 设置行高
  173.     // rows 为一个对象数组,依次表示每一行的高度
  174.     if (!ws['!rows']) ws['!rows'] = []
  175.     ws['!rows'] = [
  176.         { hpx: 0 },
  177.         { hpx: 40 },
  178.         { hpx: 15 },
  179.         { hpx: 15 },
  180.         { hpx: 20 },
  181.         { hpx: 20 },
  182.         ...Array.apply(null, { length: dataArr().length } as any).map(() => {
  183.             return { hpx: 20 }
  184.         }),
  185.     ]
  186.     var wb = utils.book_new()
  187.     utils.book_append_sheet(wb, ws, 'Sheet1')
  188.     writeFile(wb, 'SheetJSVueAoO.xlsx')
  189. }
  190. </script>
  191. <template>
  192.     <div>
  193.         <button @click="exportFile">单元格样式</button>
  194.     </div>
  195. </template>
复制代码

十、项目地址

项目地址:https://github.com/aibujin/xlsx-js-style

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

忿忿的泥巴坨

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表