前端 读取/导入 Excel文档

情况: 需要通过Excel表,将数据导入到数据库,但是后台人员出差了,我又只会PHP,没用过node,所以只能前端导入Excel文件,然后循环调用后台的单条添加接口了。

库: Excel.js(版本4.3.0)

CDN地址:

html 复制代码
<script src="https://cdn.bootcdn.net/ajax/libs/exceljs/4.3.0/exceljs.min.js"></script>

Excel.js 中文文档:https://gitee.com/alan_scut/exceljs

下面是动态Excel表单

下面是file文件(Excel文件)获取到的对象:

下面是代码中输出的需要插入的数据:

代码:

使用方法: importExcal()

javascript 复制代码
// 全局函数执行完成后执行组件的钩子函数、组件事件、自定义事件

// 导入Excel表
async function importExcal() {
  // 文件内容 (这里是从input file里面获取到的内容)
  var file = input_file;
  // 提交后端数据的整体数组
  var data_arr = [];
  // 行程的最大列数(包含前面不变的)
  var stay_col_num = 0;

  if (file) {
    // 判断文件类型
    let filetype = file.name.split('.')[file.name.split('.').length - 1]
    let filetypes = '.xlsx,.xls'
    if (filetypes.indexOf(filetype) === -1) {
	    this.$message({
			message: '请上传 .xlsx 或 .xls 文件。',
			type: 'warning'
		})
      return;
    }
    // 读取文件文件
    const reader = new FileReader();

    // file.raw是具体的文件内容,需要看一下你获取到的是file.raw,还是file[0]即可 将文件转为 ArrayBuffer 格式
    console.log("这里是获取到的file文件内容:", file)
    // 这里要用 readAsArrayBuffer 转成buffer,因为下面读取要用到 buffer 才可以
    reader.readAsArrayBuffer(file.raw);
    reader.onload = function (event) {
      try {
        const result = event.target.result;
        var workbook = new ExcelJS.Workbook();
        // 读取 buffer 内容
        workbook.xlsx.load(result)
          .then(async function () {
            // 迭代所有sheet (如果只有一个,可以通过名称获取 var worksheet = workbook.getWorksheet('My Sheet');)
            workbook.eachSheet(async function (worksheet, sheetId) {
              // 清空数据数组
              data_arr = [];
              // 获取 形成安排 的列数(从第8列开始的), 总不会超过100天,所以写个100
              // 在这里获取 形成列的长度,是因为这里是表头,不会像内容一样出现空白单元格,造成无法获取到最终列的情况
              for (let j = 8; j <= 100; j++) {
                // 当列到 行程安排 且,j+1 不是 行程安排的时候,就是行程安排的列宽
                if (worksheet.getCell(`${getLetter(j)}2`).value == '行程安排' && worksheet.getCell(`${getLetter(j + 1)}2`).value !== '行程安排') {
                  stay_col_num = j;
                  // 如果两个都有值的话,就跳出循环
                  break;
                }
              }
              // 迭代工作表中具有值的所有行
              worksheet.eachRow(function (row, rowNumber) {
                // 数据是从第四行开始
                if (rowNumber >= 4) {
                  // data_arr.push(row.values)
                  // 每行的数据
                  let row_data = row.values;
                  // 传给后端的对象
                  let data_obj = {
                    "guest": "",
                    "name": "",
                    "sex": "",
                    "company": "",
                    "job": "",
                    "phone": "",
                    "stay": []
                  }

                  // 循环每行的数据
                  row_data.map(function (item, index, arr) {
                    // 如果是前7列,则是固定列的值,直接复制即可,否则的话则是 动态的行程安排
                    if (index <= 7) {
                      switch (index) {
                        case 2:
                          // 嘉宾类别
                          data_obj.guest = item ? item : "";
                          break;
                        case 3:
                          // 姓名
                          data_obj.name = item ? item : "";
                          break;
                        case 4:
                          // 性别
                          data_obj.sex = item ? item : "";
                          break;
                        case 5:
                          // 单位
                          data_obj.company = item ? item : "";
                          break;
                        case 6:
                          // 职务
                          data_obj.job = item ? item : "";
                          break;
                        case 7:
                          // 手机号
                          data_obj.phone = item ? item : "";
                          break;
                      }
                    } else {
                      // 行程安排(从第八列开始到形成的最后一列结束)
                      if (index >= 8 && index <= stay_col_num) {
                        if (worksheet.getCell(`${getLetter(index)}${rowNumber}`).value == '是') data_obj.stay.push(worksheet.getCell(`${getLetter(index)}3`).value);
                      }
                    }
                  })
                  // 将插入后台的数据添加进数组
                  data_arr.push(data_obj);
                }
              });
              console.log("全部需要插入数据库的数据的数组:", data_arr)
              // 这里使用了 Promise 解决在for循环内,使异步接口,进行同步提交的问题;文章后面有详细说明
              for (let i = 0; i < data_arr.length; i++) {
                let result_data = await createUser(data_arr[i]);
                if (!result_data.result) {
					// 如果出错,就跳出循环
					this.$message({
						message: `第 ${i + 1} 行数据 ${data_arr[i].name}(${data_arr[i].phone}),由于 ${result_data.msg} 导入失败`,
						type: 'error'
					})
					// 跳出循环
                	break;
                }
              }
            });
          });
      } catch (err) {
      	this.$message({
			message: '读取文件错误',
			type: 'error'
		})
        console.log('err', err);
      }
    };
  } else {
  	this.$message({
		message: '请选择文件',
		type: 'error'
	})
  }
}

// 添加用户信息接口
async function createUser(data) {
  return await new Promise(function (resolve, reject) {
    // 处理异步逻辑时候调用resolve和reject函数
    axios({
      method: 'POST',
      url: `${base_url}/api/add`,
      headers: {
        // 没有可以不要token
        // authorization: `bearer ${token}`
      },
      // 数据
      data: data
    }).then(res => {
      let resp = res.data;
      if (resp.code == 1) {
        if (resp.data.code == 200) {
          resolve({
            "result": true
          });
        }
      } else {
        resolve({
          "result": false,
          "msg": resp.msg
        });
      }
    }).catch(req => {
      reject({
        "result": false,
        "msg": ""
      });
    });
  });
}

// 获取第N个字母
function getLetter(num) {
  return String.fromCharCode(64 + num);
}

代码中用到的方法总结:

新建工作簿

var workbook = new ExcelJS.Workbook();

读取 buffer 内容

workbook.xlsx.load(data).then(function() {

// 其他代码

});

迭代所有sheet

workbook.eachSheet(function(worksheet, sheetId) {

// 其他代码

});

按名称获取表格

var worksheet = workbook.getWorksheet('My Sheet');

按ID获取表格

var worksheet = workbook.getWorksheet(1);

迭代工作表中具有值的所有行

worksheet.eachRow(function(row, rowNumber) {

console.log('Row:' + rowNumber + ' = ' + JSON.stringify(row.values));

});

获取单元格(A2)

var collectcell = worksheet.getCell('A2');

for循环内,使异步接口变成同步提交

我文章的地址:前端JS for循环内异步接口变成同步提交(JavaScript for循环异步变同步)

遇见的一些问题:
1. Excel.JS 支持的数据读取方式不同,获取的数据类型不同。例如:filestreambuffer

另外说一下

有兴趣的朋友也可以试试 SheetJS ,感觉好像功能更多一些,下次我再需要用到excel的时候也会尝试一下的。
SheetJS中文文档:https://github.com/rockboom/SheetJS-docs-zh-CN

相关推荐
圣光SG4 分钟前
Java类与对象及面向对象基础核心详细笔记
java·前端·数据库
Jinuss13 分钟前
源码分析之React中的useImperativeHandle
开发语言·前端·javascript
ZC跨境爬虫25 分钟前
CSS核心知识点与定位实战全解析(结合Playwright爬虫案例)
前端·css·爬虫
Jinuss27 分钟前
源码分析之React中的forwardRef解读
前端·javascript·react.js
mengsi5529 分钟前
Antigravity IDE 在浏览器上 verify 成功但本地 IDE 没反应 “开启Tun依然无济于事” —— 解决方案
前端·ide·chrome·antigravity
Можно43 分钟前
pages.json 和 manifest.json 有什么作用?uni-app 核心配置文件详解
前端·小程序·uni-app
hzhsec1 小时前
钓鱼邮件分析与排查
服务器·前端·安全·web安全·钓鱼邮件
#做一个清醒的人1 小时前
Electron 保活方案:用子进程彻底解决原生插件崩溃问题
前端·electron·node.js
四千岁1 小时前
Obsidian + jsDelivr + PicGo = 免费无限图床:一键上传,全平台粘贴即发
前端·程序员·github