前端实现Excel导出【xlsx】【xlsx-js-style】

发布时间 2023-11-07 21:21:19作者: ^Mao^

最终效果

场景

有的时候我们需要根据服务端返回的数据来导出excel表格

优化一:设置单元格样式

比如:可以调节背景色、字体样式、border

xlsx基础库不提供样式设置,可以使用xlsx-js-style库,这个库是xlsx库的fork版本,并添加了样式定义

详细样式可以查看https://github.com/gitbrent/xlsx-js-style/

  1. 安装插件
npm i -s xlsx-js-style
  1. 导出单元格带样式
const data = [
    ["zs", 20, "1991-06-01"],
    ["ww", 14, "2001-09-01"],
    ["ls", 31, "1993-04-14"],
  ];
const workbook = XLSX.utils.book_new();
const worksheet = XLSX.utils.json_to_sheet(data);

// 设置单元格属性
worksheet["A1"].s = {
  font: { bold: true },
  alignment: {
    horizontal: "center",
    vertical: "center",
  },
  fill: {
    fgColor: {
      rgb: "FF0000",
    },
  },
};

XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");
XLSX.writeFile(workbook, "data.xlsx");

优化二:去除默认表头,表头自定义

const data = [
  ['zs', 20, '1991-06-01'],
  ['ww', 14, '2001-09-01'],
  ['ls', 31, '1993-04-14'],
]

// 表头设置
data.unshift(['姓名', '年龄', '出生日期'])

const workbook = XLSX.utils.book_new()
const worksheet = XLSX.utils.json_to_sheet(data, {
  skipHeader: true,
})

XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
XLSX.writeFile(workbook, 'data.xlsx')

优化三:设置列宽

const data = [
  ['zs', 20, '1991-06-01'],
  ['ww', 14, '2001-09-01'],
  ['ls', 31, '1993-04-14'],
]

const workbook = XLSX.utils.book_new()
const worksheet = XLSX.utils.json_to_sheet(data, {
  skipHeader: true,
})

// 设置列宽
worksheet['!cols'] = [
  {
    wpx: 200,
  },
]

XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
XLSX.writeFile(workbook, 'data.xlsx')

优化四:合并单元格

const data = [
  ['zs', 20, '1991-06-01'],
  ['ww', 14, '2001-09-01'],
  ['ls', 31, '1993-04-14'],
]

const workbook = XLSX.utils.book_new()
const worksheet = XLSX.utils.json_to_sheet(data, {
  skipHeader: true,
})

// s 表示要合并的单元格范围的左上角单元格,r 表示该单元格的行号,c 表示该单元格的列号,行列号从 0 开始计数。
//    所以 { r: 0, c: 0 } 表示第 1 行第 1 列的单元格,即 A1 单元格。
// e 表示要合并的单元格范围的右下角单元格,其含义与 s 相同。
//    所以 { r: 1, c: 1 } 表示第 2 行第 2 列的单元格,即 B2 单元格。
// 因此,{ s: { r: 0, c: 0 }, e: { r: 1, c: 1 } } 表示要合并第 1 行第 1 列和第 2 行第 2 列之间的元格。
// 注意,合并会以开始位置单元格中的内容为准,所以合并后的单元格中的内容为 A1 单元格中的内容。
worksheet['!merges'] = [
  {
    s: {
      r: 0,
      c: 0,
    },
    e: {
      r: 1,
      c: 1,
    },
  },
]

XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
XLSX.writeFile(workbook, 'data.xlsx')

终极版

实现优化一、二、三

import { exportExcel } from '@/utils/excel'

const exportClick6 = () => {
  // 页面上展示的列, 比如使用了element-ui中的table组件
  const columns = [
    {
      prop: 'name',
      label: '姓名',
      width: 150,
      excelStyle: {
        font: { bold: true },
        alignment: {
          horizontal: 'center',
          vertical: 'center',
        },
        fill: {
          fgColor: {
            rgb: 'FFFF00',
          },
        },
      },
    },
    {
      prop: 'age',
      label: '年龄',
      width: 300,
    },
    {
      prop: 'date',
      label: '出生日期',
      excelStyle: {
        fill: {
          fgColor: {
            rgb: '00FFFF',
          },
        },
      },
    },
  ]
  const tableData = [
    {
      name: 'zs',
      age: 20,
      date: '1991-06-01',
      address: '广州市',
    },
    {
      name: 'ww',
      age: 14,
      date: '2001-09-01',
    },
    {
      name: 'ls',
      age: 31,
      date: '1993-04-14',
    },
  ]

  exportExcel('test', tableData, columns)
}

utils/excel

import * as XLSX from 'xlsx-js-style'

export function exportExcel(excelName, data, columns) {
  const newData = []
  const keys = columns.map((item) => item['prop'])
  const headers = columns.map((item) => item['label'])

  data.forEach((item) => {
    const row = []
    for (let key of keys) {
      row.push(item[key])
    }
    newData.push(row)
  })
  // 添加表头
  newData.unshift(headers)

  const workbook = XLSX.utils.book_new()
  const worksheet = XLSX.utils.json_to_sheet(newData, {
    skipHeader: true,
  })

  // 设置列宽
  const columnsWidth = columns.map((item) => {
    return {
      wpx: item.width,
    }
  })
  worksheet['!cols'] = columnsWidth

  // 设置表头样式
  columns.forEach((item, index) => {
    if (item['excelStyle']) {
      const cell = indexToLetters(index) + 1
      worksheet[cell].s = item['excelStyle']
    }
  })

  XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
  XLSX.writeFile(workbook, `${excelName}.xlsx`)
}

function indexToLetters(i) {
  if (i >= 0 && i <= 25) {
    return String.fromCharCode(65 + i)
  } else {
    return undefined
  }
}

参考文章

https://blog.csdn.net/qq_42611074/article/details/130580395