js 使用XLSX插件表格读取(封装版)复制即可用版

项目中,多次使用到了读取表格。考虑到后续可能会修改表头(新增必填标志,或者删除必填标志,在后面加(***)注解什么的),不改变主体部分只校验的主体部分,根据自己手动传值判断第几行是表头

1.安装插件

npm install xlsx

2.封装xlsx读取部分代码  vueExcelHandler.js

import * as XLSX from 'xlsx'; // 确保你已经安装了 xlsx 库

// 清洗表头字符串
function cleanHeader(header) {
  // 去除所有空格
  let cleanedHeader = header.replace(/\s+/g, '');
  // 去除星号
  cleanedHeader = cleanedHeader.replace(/\*+/g, '');
  // 使用循环确保去除所有的括号及其内容
  while (cleanedHeader.includes('(') && cleanedHeader.includes(')')) {
    cleanedHeader = cleanedHeader.replace(/\(.*?\)/g, '');
  }
  while (cleanedHeader.includes('(') && cleanedHeader.includes(')')) {
    cleanedHeader = cleanedHeader.replace(/(.*?)/g, '');
  }
  // 转换为小写
  return cleanedHeader.toLowerCase();
}
function validateSheetHeaders(worksheet, requiredColumns,headerRowNumber) {
  // const headerRow = XLSX.utils.sheet_to_json(worksheet, { header: headerRowNumber })[0];
  // 从指定行获取表头
  const headerRow = getRow(worksheet, headerRowNumber-1);
  console.log('原始表头:', headerRow);
  const cleanedHeaderRow = headerRow.map(cleanHeader);
  console.log('清洗后的表头:', cleanedHeaderRow);
  const requiredColumnsClean = requiredColumns.map(cleanHeader);
  console.log('必需的列(清洗后):', requiredColumnsClean);
  // 创建一个映射关系,用于检查必需的列是否全部存在
  const headerMap = new Map(cleanedHeaderRow.map((col, index) => [col, index]));
  // 检查必需的列是否全部存在
  const missingColumns = requiredColumnsClean.filter(col => !headerMap.has(col));
  if (missingColumns.length > 0) {
    console.error(`缺少以下必需的列:${missingColumns.join(', ')}`);
    return false;
  }
  return true;
}

function getRow(worksheet, rowIndex) {
  const range = XLSX.utils.decode_range(worksheet['!ref']);
  const row = [];

  for (let C = range.s.c; C <= range.e.c; ++C) {
    const cell = worksheet[XLSX.utils.encode_cell({ c: C, r: rowIndex })];
    row.push(cell ? XLSX.utils.format_cell(cell) : '');
  }

  return row;
}
// 文件读取和处理函数
function processExcelFile(file, config,headerd) {
  const requiredColumns = config.requiredColumns;
  const fieldMap = config.fieldMap || {};
  const callback = config.callback;
  const headerRowNumber = config.headerRowNumber || 1; // 默认表头在第1行
  const reader = new FileReader();
  reader.onload = (e) => {
    const data = e.target.result;
    let workbook;
    if (typeof data === 'string') { // 对于旧版xlsx,可能直接是二进制字符串
      workbook = XLSX.read(data, {type: 'binary'});
    } else { // 对于新版xlsx,通常为ArrayBuffer
      workbook = XLSX.read(new Uint8Array(data), {type: 'array'});
    }

    // 获取第一个工作表
    const worksheet = workbook.Sheets[workbook.SheetNames[0]];
    console.log(worksheet)
    // 验证表头是否符合要求
    if (!validateSheetHeaders(worksheet, requiredColumns,headerRowNumber)) {
      callback(null, '表头不符合要求');
      return;
    }
  
    // 读取指定行作为表头
    const actualHeaderRow = getRow(worksheet, headerRowNumber-1);
    const cleanedActualHeaderRow = actualHeaderRow.map(cleanHeader);
    console.log('实际使用的表头(清洗后):', cleanedActualHeaderRow);

    // 动态构建fieldMap
    const dynamicFieldMap = {};
    requiredColumns.forEach((col, index) => {
      const cleanedCol = cleanHeader(col);
      if (cleanedActualHeaderRow.includes(cleanedCol)) {
        dynamicFieldMap[cleanedCol] = fieldMap[cleanedCol] || cleanedCol;
      }
    });
    console.log(requiredColumns)
    // 获取数据行的范围
    const range = XLSX.utils.decode_range(worksheet['!ref']);
    const startRow = range.s.r + headerRowNumber; // 数据从表头之后的第一行开始
    const endRow = range.e.r;

    // 读取数据行
    let excelData = [];
    console.log(cleanedActualHeaderRow)
    for (let R = startRow; R <= endRow; ++R) {
      const row = {};
      cleanedActualHeaderRow.forEach((cleanedKey, index) => {
        // 编码单元格的位置
        const cellRef = XLSX.utils.encode_cell({ c: index, r: R });
        const cell = worksheet[cellRef];
        if (cell && cell.t) {
          row[dynamicFieldMap[cleanedKey] || cleanedKey] = XLSX.utils.format_cell(cell);
        }
      });
   
      excelData.push(row);
    }
    // 过滤掉空白行
    excelData = excelData.filter(row => Object.values(row).some(value => value !== ''));
    // 执行回调函数
    callback(excelData);
  };

  reader.readAsArrayBuffer(file); // 读取为ArrayBuffer
}

export { processExcelFile };

2.多个表头需要校验,也一起封装起来,避免后面修改,多次改页面造成失误  mainBody.js

export default class ConfigManager {
  constructor() {
    this.configs = {
      config1: {
        requiredColumns: ['姓名', '年龄', '性别', '职位'],
        fieldMap: {
           //对应后端字段
          '姓名': 'name',
          '年龄': 'age',
          '性别': 'gender',
          '职位': 'position'
        },
        callback: (excelData) => {
          console.log('Config 1:', excelData);
        }
      },
      config2: {
        requiredColumns: ['姓名', '年龄', '性别', '职位'],
        fieldMap: {
          '姓名': 'name',
          '年龄': 'age',
          '性别': 'gender',
          '职位': 'position'
        },
        callback: (excelData) => {
          console.log('Config 2:', excelData);
        }
      },
      // 可以添加更多的配置...
    };
  }

  getConfig(configName) {
    if (this.configs.hasOwnProperty(configName)) {
      return this.configs[configName];
    } else {
      throw new Error(`Configuration '${configName}' not found.`);
    }
  }
}

3.使用

import { processExcelFile } from '@/你的路径/vueExcelHandler.js';
import ConfigManager  from '@/你的路径/mainBody.js';
上传框
<input type="file" @change="handleFileUpload" name="" ref="fjset"> 


handleFileUpload(event) {
      const files = event.target.files || event.dataTransfer.files;

      if (files.length > 0) {
        const file = files[0];

        const imgType = file.type === "application/vnd.ms-excel";

        const isLt10M = file.size / 1024 / 1024 < 10;
        if (!isLt10M) {
          alert("文件大小不能大于10M!");
          this.$refs['fjset'].value = '';
          return;
        }
        // 选择需要的配置名称
        const configName = 'config1'; // 或者 'config2'
        try {
          const config = this.configManager.getConfig(configName);
          config.headerRowNumber =2; // 假设表头在第2行
          config.callback = (excelData, error) => {
            this.$refs['fjset'].value = ''; //清空输入框
            if (error) {
              alert(error+1);
            } else {
              this.tableData = excelData;
              console.log(excelData);
            }
          };
          processExcelFile(file, config);
        } catch (error) {
          alert(error.message);
          this.$refs['fjset'].value = ''; // 配置加载错误时清空输入框
        }
      }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值