vue3中使用xlsx库读取Excel数据

需求背景

一张总域名表包含上千个不同的域名,一张新域名表包含若干个域名,新表中的域名可能有部分与总表重复,需要将两张表数据对比分析,并将新表的非重复部分导出为Excel文件。

实现效果如下,上传总表和新表之后,立即显示出新表的域名冗余状态。

读取总表

代码

<input type="file" @change="domainUpload" accept=".xlsx, .xls" ref="domainInput" />

import * as XLSX from 'xlsx';
type FilteredRow = [string, string]; // 表示过滤后的行
type ExcelData = [string][]; // 表示所有行的数组
const excelData = ref<ExcelData>([]);
type FilteredData = [string, string][]; // 表示所有行的数组
const filteredData = ref<FilteredData>([]);
const domainInput = ref<HTMLInputElement | null>(null); //总表输入框
const newFileInput = ref<HTMLInputElement | null>(null); //新表输入框
const loading = ref<boolean>(false);
const allDomains = ref<Array<string>>([]); //存放所有域名值

const domainUpload = (event: Event) => {
  const input = event.target as HTMLInputElement;
  const file = input.files ? input.files[0] : null;
  if (!file) return;
  if (!file.name.endsWith('.xlsx') && !file.name.endsWith('.xls')) {
    ElMessage.error('请上传Excel文件');
    if (domainInput.value) {
      domainInput.value.value = ''; // 清空文件输入框
    }
    return;
  }
  const reader = new FileReader();
  reader.onload = (e) => {
    // e.target.result --> FileReader 完成读取操作后的结果
    const arrayBuffer = e.target ? (e.target.result as ArrayBuffer) : null;
    if (!arrayBuffer) return;
    // 将 ArrayBuffer(原始二进制数据) 转换为 Uint8Array
    // XLSX 库期望接收 Uint8Array 格式以解析 Excel
    const data = new Uint8Array(arrayBuffer);
    const workbook = XLSX.read(data, { type: 'array' }); //开始解析
    const sheetName = workbook.SheetNames[0];
    const worksheet = workbook.Sheets[sheetName];
    const jsonData: [string][] = XLSX.utils.sheet_to_json(worksheet, {
      header: 1
    }); //第一列的所有数据
    allDomains.value = jsonData.slice(1).map((item) => item[0]); // 去除域名后的第一列所有数据
  };
  reader.readAsArrayBuffer(file);  //result as ArrayBuffer的原因
};

FileReader介绍

FileReader是一个web api(浏览器提供),用于异步读取文件内容,可以将文件内容读取为不同的格式,包括

  • 文本(readAsText)
  • ArrayBuffer(readAsArrayBuffer)
  • Data URL(readAsDataURL)
  • 二进制字符串(readAsBinaryString)

reader.readAsArrayBuffer

Excel 本质是二进制数据。FileReader 的 readAsArrayBuffer 方法提供了 ArrayBuffer,这是一种表示原始二进制数据的有效方式。ArrayBuffer 可以轻松转换为其他类型的数据视图,如 Uint8Array(Excel 文件的二进制数据本质上是以字节(8位)为单位的),后者是 XLSX 库处理 Excel 文件时推荐的输入格式之一。

onload

onload表读取成功完成时的事件,需要自定义,reader.readAsArrayBuffer时会触发

sheet_to_json

XLSX.utils.sheet_to_json将 Excel 工作表转换为 JS 对象或数组。

读取新表

<input type="file" @change="newFileUpload" accept=".xlsx, .xls" ref="newFileInput" />

const newFileUpload = (event: Event) => {
  const input = event.target as HTMLInputElement;
  const file = input.files ? input.files[0] : null;
  if (!file) return;
  if (!file.name.endsWith('.xlsx') && !file.name.endsWith('.xls')) {
    ElMessage.error('请上传Excel文件');
    if (newFileInput.value) {
      newFileInput.value.value = ''; // 清空文件输入框
    }
    return;
  }
  const reader = new FileReader();
  reader.onload = async (e) => {
    const arrayBuffer = e.target ? (e.target.result as ArrayBuffer) : null;
    if (!arrayBuffer) return;
    const data = new Uint8Array(arrayBuffer);
    const workbook = XLSX.read(data, { type: 'array' });
    const sheetName = workbook.SheetNames[0];
    const worksheet = workbook.Sheets[sheetName];
    const jsonData: [string][] = XLSX.utils.sheet_to_json(worksheet, {
      header: 1
    }); //第一列的所有数据
    excelData.value = jsonData.slice(1); // 去除域名后的第一列所有数据
    await filterData(false);   //过滤数据,将冗余信息可视化
  };
  reader.readAsArrayBuffer(file);
};

对比&导出

<div class="excel-container">
      <Box v-show="filteredData.length">
        <el-table border :data="filteredData" style="width: 100%">
          <el-table-column type="index" label="序号" width="80" />
          <el-table-column prop="0" label="域名" width="280">
            <template #default="scope">
              <div :class="duplicateClass(scope.row)">{{ scope.row[0] }}</div>
            </template>
          </el-table-column>
          <el-table-column prop="1" label="状态" width="100">
            <template #default="scope">
              <div :class="duplicateClass(scope.row)">
                {{ scope.row[1] === '1' ? '冗余' : '新值' }}
              </div>
            </template>
          </el-table-column>
          <el-table-column label="操作" width="200">
            <template #default="scope">
              <el-button link type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button>
            </template>
          </el-table-column>
        </el-table>
      </Box>
    </div>
const filterData = async (closed: boolean) => {
  while (!allDomains.value.length) {
    loading.value = true;
  }
  loading.value = false;
  const needFilter = ref<ExcelData | FilteredData>([]);
  // 将数据添加新属性,1表示冗余,0表示新值
  if (closed) {
    //关闭编辑框时过滤filteredData
    needFilter.value = filteredData.value;
  } else {
    //点击过滤按钮时过滤excelData
    needFilter.value = excelData.value;
  }
  filteredData.value = needFilter.value.map((row) => {
    const domain = row[0];
    const isDuplicate = allDomains.value.includes(domain);
    return [domain, isDuplicate ? '1' : '0'];
  });
};

const exportExcel = () => {
  // 将保留的数据添加上表头
  const outputData = [
    ['新值域名'],
    ...filteredData.value.filter((row) => row[1] === '0').map((row) => [row[0]])
  ];
  // 创建一个新的工作簿
  const worksheet = XLSX.utils.aoa_to_sheet(outputData);
  const workbook = XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
  // 导出 Excel 文件,以 年月日时分秒 时间命名
  let newFileName = new Date()
    .toLocaleString()
    .replace(/\//g, '-')
    .replace(' ', '_');
  XLSX.writeFile(workbook, `${newFileName}.xlsx`);
};

const duplicateClass = (row: [string, string]) => {
  return row[1] === '1' ? 'duplicateItem' : '';
};

XLSX.utils.aoa_to_sheet

将数组的数组(Array of Arrays,简称 AoA)转换为 Excel 工作表对象

XLSX.utils.book_new

创建一个新的空 Excel 工作簿对象

XLSX.utils.book_append_sheet

将工作表添加到工作簿中,参数依次为:工作簿对象、工作表对象、工作表名称

XLSX.writeFile

将工作簿写入文件,用于保存 Excel 文件到本地文件系统或触发文件下载

// 创建数据
const data = [["Name", "Age"], ["John", 30], ["Jane", 25]];
// 创建工作簿
const wb = XLSX.utils.book_new();
// 创建工作表
const ws = XLSX.utils.aoa_to_sheet(data);
// 将工作表添加到工作簿
XLSX.utils.book_append_sheet(wb, ws, "People");
// 保存文件
XLSX.writeFile(wb, "people.xlsx");

工作簿WorkBook是整个 Excel 文件,工作表Worksheet是工作簿中的一个单独的"页面"或数据网格

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值