Vue3-导出导入excel

功能

主要实现excel导入导出功能,同时具有合并单元格,美化单元格等功能,引用依赖包exceljs、file-saver,好像也没有什么要介绍的,可以看看官网文档然后直接使用了

导入依赖包

javascript 复制代码
pnpm install exceljs file-saver @types/file-saver

封装Excel帮助类(excelHelper.js)

javascript 复制代码
import ExcelJS from 'exceljs'
import FileSaver from 'file-saver'
import { cloneDeep } from 'lodash'

/**
 * 读取excel文件
 * @param {object} file 文件
 * @param {String} sheetName 获取工作表名称
 * @returns 
 */
export async function readExcelFile(file, sheetName) {
    const arrayBuffer = file.arrayBuffer()
    const result = []
    const workbook = new ExcelJS.Workbook()
    await workbook.xlsx.load(arrayBuffer)
    const worksheet = workbook.getWorksheet(sheetName || 1)
    worksheet.eachRow((row, rowNumber) => {
        console.log(rowNumber)
        const rowData = []
        result.push(rowData)
        row.eachCell((cell, colNumber) => {
            rowData.push(cell.value)
            console.log(colNumber)
        })
    })
    return result
}
/**
 * 
 * 数据导出excel
 * @param {String} excelOpt.fileName   导出文件名
 * @param {String} excelOpt.configs.sheetName 工作表名称,默认从sheet1开始
 * @param {Array[Array]} excelOpt.configs.headers  表格头部 eg:[['标题1','标题2'],['标题3','标题4']]
 * @param {Array[Array]} excelOpt.configs.data   表格数据
 * @param {Array[Object]} excelOpt.configs.merges 合并信息 eg:[row: 0, col: 0, rowspan: 3, colspan: 1]
 * @param {Array[object]} excelOpt.configs.views 工作表视图配置
 * @param {Array[Number]} config.columnsWidth 每个字段列对应的宽度
 * @param {Object} excelOpt.configs.protect 工作表保护【此配置会保护全表,一般推荐只针对单元格进行保护配置】
 * @param {Array} excelOpt.configs.fields 辅助导出顺序
 * 
 */
export function exportExcel(excelOpt) {
    if (!excelOpt) return
    const opt = cloneDeep(excelOpt)
    console.dir(excelOpt.sheetInfos[0])
    const dataOptions = {
        fileName: opt.fileName || `导出excel文件【${Date.now()}】.xlsx`,
        worksheets: []
    }
    if (!Array.isArray(opt.sheetInfos)) {
        opt.sheetInfos = [opt.sheetInfos]
    }
    opt.sheetInfos.forEach(item => {
        //对象根据fields进行组装数组数据
        let data = item.data.map(obj => {
            return item.fields.map(key => {
                return obj[key]
            })
        })
        let excelData = [].concat(item.headers).concat(data)
        let merges = item.merges.map(m => {
            return [m.row + 1, m.col + 1, m.row + m.rowspan, m.col + m.colspan]
        })
        let excelAttrs = item.attrs.map(attr => {
            attr.rowStart += 1;
            attr.rowEnd += 1;
            attr.colStart += 1;
            attr.colEnd += 1;
            return attr
        })
        dataOptions.worksheets.push({
            data: excelData,
            merges: merges,
            attrs: excelAttrs,
            views: item.views,
            columnsWidth: item.columnsWidth,
            protect: item.protect,
            sheetName: item.sheetName
        })
    })
    createExcel(dataOptions)
}
// 创建Excel文件方法
async function createExcel(options) {
    if (!options.worksheets.length) return;
    // 创建工作簿
    const workbook = new ExcelJS.Workbook();
    for (let i = 0; i < options.worksheets.length; i++) {
        const sheetOption = options.worksheets[i];
        // 创建工作表
        const sheet = workbook.addWorksheet(sheetOption.sheetName || 'sheet' + (i + 1));
        // 添加数据行
        sheet.addRows(sheetOption.data);
        // 配置视图
        sheet.views = sheetOption.views;
        // 单元格合并处理【开始行,开始列,结束行,结束列】
        if (sheetOption.merges) {
            sheetOption.merges.forEach((item) => {
                sheet.mergeCells(item);
            });
        }
        // 工作表保护
        if (sheetOption.protect) {
            // const res = await sheet.protect(sheetOption.protect.password, sheetOption.protect.options);
            await sheet.protect(sheetOption.protect.password, sheetOption.protect.options);
        }
        // 单元格样式处理
        if (sheetOption.attrs.length) {
            sheetOption.attrs.forEach((item) => {
                const attr = item.attr || {};
                // 获取开始行-结束行; 开始列-结束列
                const rowStart = item.rowStart;
                const rowEnd = item.rowEnd;
                const colStart = item.colStart;
                const colEnd = item.colEnd;
                if (rowStart) { // 设置行
                    for (let r = rowStart; r <= rowEnd; r++) {
                        // 获取当前行
                        const row = sheet.getRow(r);
                        if (colStart) { // 列设置
                            for (let c = colStart; c <= colEnd; c++) {
                                // 获取当前单元格
                                const cell = row.getCell(c);
                                Object.keys(attr).forEach((key) => {
                                    // 给当前单元格设置定义的样式
                                    cell[key] = attr[key];
                                });
                            }
                        } else {
                            // 未设置列,整行设置【大纲级别】
                            Object.keys(attr).forEach((key) => {
                                row[key] = attr[key];
                            });
                        }
                    }
                } else if (colStart) { // 未设置行,只设置了列
                    for (let c = colStart; c <= colEnd; c++) {
                        // 获取当前列,整列设置【大纲级别】
                        const column = sheet.getColumn(c);
                        Object.keys(attr).forEach((key) => {
                            column[key] = attr[key];
                        });
                    }
                } else {
                    // 没有设置具体的行列,则为整表设置
                    Object.keys(attr).forEach((key) => {
                        sheet[key] = attr[key];
                    });
                }
            })
        }
        // 列宽设置
        if (sheetOption.columnsWidth) {
            for (let i = 0; i < sheet.columns.length; i++) {
                sheet.columns[i].width = sheetOption.columnsWidth[i]
            }
        }
    }

    // 生成excel文件
    workbook.xlsx.writeBuffer().then(buffer => {
        // application/octet-stream 二进制数据
        FileSaver.saveAs(new Blob([buffer], { type: 'application/octet-stream' }), options.fileName)
    })
}

使用(导出,导入)

javascript 复制代码
//导出
const exportExcelFn = () => {
  const data = [{
    index: 1,
    title1: 'title1-1',
    title2: 'title1-2',
    title3: 'title1-3',
    title4: 'title1-4',
    title5: 'title1-5',
    title6: 'title1-6',
    title7: 'title1-7',
    title8: 'title1-8',
    title9: 'title1-9',
    title10: 'title1-10',
  },
  {
    index: 2,
    title1: 'title2-1',
    title2: 'title2-2',
    title3: 'title2-3',
    title4: 'title2-4',
    title5: 'title2-5',
    title6: 'title2-6',
    title7: 'title2-7',
    title8: 'title2-8',
    title9: 'title2-9',
    title10: 'title2-10',
  }]
  const opt = {
    fileName: '积分明细.xlsx',
    sheetInfos: [
      {
        fields: ['index', 'title1', 'title2', 'title3', 'title4', 'title5', 'title6', 'title7', 'title8', 'title9', 'title10'],
        headers: [['序号', '标题1', '标题2', '标题3', '标题4', '标题5', '标题6', '标题7', '标题8', '标题9', '标题10']],
        data: data,
        merges: [
          // { row: 1, col: 1, rowspan: 11, colspan: 1 },
        ],
        attrs: [],
        columnsWidth: [20, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
        sheetName: '导出数据测试'
      }
    ]
  }
  //设置单元格样式
  opt.sheetInfos.map(item => {
    item.attrs.push({
      rowStart: 0,
      rowEnd: item.headers.length + item.data.length,
      colStart: 0,
      colEnd: item.headers[0].length - 1,
      attr: {
        alignment: { vertical: "middle", horizontal: "center" },
        // border: {
        //   top: { style: "thin" },
        //   left: { style: "thin" },
        //   bottom: { style: "thin" },
        //   right: { style: "thin" }
        // }
      }
    })
    // 设置表头填充颜色,字体加粗
    item.attrs.push({
      rowStart: 0,
      rowEnd: item.headers?.length - 1,
      colStart: 0,
      colEnd: item.headers[0].length - 1,
      attr: {
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "99CCFF" }
        },
        font: {
          bold: true
        }
      }
    })
  })
  exportExcel(opt)
}
javascript 复制代码
<script setup>
import { readExcelFile } from '@/utils/excelHelper'

const fileUploadFn = async (file) => {
  const excelData = await readExcelFile(file)
  console.log('Excel Data:', excelData)
  return false;
}
</script>

<template>
  <div>
    <el-upload :before-upload="fileUploadFn" accept=".xlsx, .xls">
      <el-button type="primary" class="upload">上传</el-button>
    </el-upload>
  </div>
</template>
相关推荐
徐同保16 小时前
vue 在线预览word和excel
vue.js·word·excel
kaixin_啊啊20 小时前
计算机二级office操作技巧——Excel篇
excel
~在杰难逃~1 天前
关于订单信息的Excel数据分析报告
笔记·数据分析·excel·数据分析报告
生产队队长2 天前
SpringBoot2:web开发常用功能实现及原理解析-整合EasyExcel实现Excel导入导出功能
spring boot·excel
麋鹿会飞但不飘2 天前
EasyExcel拿表头(二级表头)爬坑,invokeHeadMap方法
java·spring boot·excel
Eiceblue2 天前
Python 实现Excel XLS和XLSX格式相互转换
vscode·python·pycharm·excel
if时光重来2 天前
springboot项目实现导出excel动态设置表头
spring boot·后端·excel
我是Superman丶2 天前
【工具】Java Excel转图片
java·python·excel
說詤榢2 天前
判断2个excel文件差异的条数
excel
镜花照无眠2 天前
Excel爬虫使用实例-百度热搜
爬虫·excel