Uniapp开发微信小程序引入xlsx引发的血案

前言

最近公司需要开发微信小程序,使用的是uniapp来开发,然后有个功能需求需要用户将上传的excel文件提取出来并显示,于是我通过DeepSeek帮助引入了XLSX组件,发现上传超过了2M限制,就算分包也不成功,最后终于解决了,现在总结一下分享出来。

准备工作

操作步骤

刚开始我试了好多办法,如下所示:
方法一: xlsx.mini

// 单独引入,android是成功,但是ios有问题
import { read, utils } from 'xlsx/dist/xlsx.mini.min';

uploadExcelTemp() {
      let toolResponses = [];
      wx.chooseMessageFile({
        count: 1, // 最多选择 1 个文件
        type: 'file', // 关键:指定为普通文件类型
        extension: ['.xlsx','xls'], // 限制文件类型为 .xlsx
        success: async (res) => {
          console.log('---chooseMessageFile success:', res)
          const filePath = res.tempFiles[0].path;
          try {
            // 获取文件管理器
            const fs = uni.getFileSystemManager();

            // 读取文件数据 (Base64格式)
            const fileData = await new Promise((resolve, reject) => {
              fs.readFile({
                filePath: filePath,
                encoding: 'base64', // 重要!必须使用base64编码
                success: res => resolve(res.data),
                fail: reject
              });
            });
            const arrayBuffer = uni.base64ToArrayBuffer(fileData); // 返回ArrayBuffer
            // 如果需要字符串,转换ArrayBuffer为字符串
            const binaryString = Array.from(new Uint8Array(arrayBuffer))
                .map(byte => String.fromCharCode(byte))
                .join('');
            // 将Base64转换为二进制数据
            // const binaryString = atob(fileData);

            // 读取Excel工作簿
            const workbook = XLSX.read(binaryString, {type: 'binary'});

            // 获取第一个工作表
            const firstSheetName = workbook.SheetNames[0];
            const worksheet = workbook.Sheets[firstSheetName];

            // 转换为JSON
            const jsonData = XLSX.utils.sheet_to_json(worksheet);

            console.log('转换后的JSON数据:', jsonData);
          } catch (error) {
            console.log('---chooseMessageFile error:', error)
          }
        },
        fail: (err) => {
          console.log('---chooseMessageFile err:', err)
        }
      });
    },

结果:失败!android成功,ios失败

方法二:exceljs

// 1. 安装依赖(终端执行)
// npm install exceljs@4

// 2. 在页面/组件中实现
import ExcelJS from 'exceljs/dist/exceljs.min.js'; // 仅引入核心min版

export default {
  methods: {
    async chooseExcelFile() {
      try {
        // 选择文件
        const [file] = await this.uniChooseFile();
        console.log('选中文件:', file);
        
        // 读取文件内容
        const arrayBuffer = await this.readFile(file.path);
        
        // 解析Excel
        const jsonData = await this.parseExcel(arrayBuffer);
        console.log('解析结果:', jsonData);
        
        // 使用数据(示例:展示前5行)
        this.excelData = jsonData.slice(0, 5);
      } catch (error) {
        console.error('处理失败:', error);
        uni.showToast({ title: '文件处理失败', icon: 'none' });
      }
    },
    
    // 封装文件选择
    uniChooseFile() {
      return new Promise((resolve, reject) => {
        uni.chooseMessageFile({
          count: 1,
          type: 'file',
          extension: ['.xlsx', '.xls'],
          success: res => resolve(res.tempFiles),
          fail: reject
        });
      });
    },
    
    // 封装文件读取
    readFile(filePath) {
      return new Promise((resolve, reject) => {
        const fs = uni.getFileSystemManager();
        fs.readFile({
          filePath,
          // 注意:小程序环境必须使用 arrayBuffer 格式
          encoding: 'binary',
          success: res => {
            // 转换为 ArrayBuffer
            const buffer = new Uint8Array(res.data.length);
            for (let i = 0; i < res.data.length; i++) {
              buffer[i] = res.data.charCodeAt(i) & 0xFF;
            }
            resolve(buffer);
          },
          fail: reject
        });
      });
    },
    
    // Excel解析核心方法
    async parseExcel(arrayBuffer) {
      const workbook = new ExcelJS.Workbook();
      await workbook.xlsx.load(arrayBuffer);
      
      const worksheet = workbook.getWorksheet(1); // 获取第一个工作表
      if (!worksheet) throw new Error('工作表不存在');
      
      const jsonData = [];
      const headers = [];
      
      // 提取表头(第一行)
      worksheet.getRow(1).eachCell((cell, colIndex) => {
        headers[colIndex] = cell.value?.toString() || `列${colIndex}`;
      });
      
      // 处理数据行(从第二行开始)
      worksheet.eachRow((row, rowIndex) => {
        if (rowIndex === 1) return; // 跳过表头
        
        const rowData = {};
        row.eachCell((cell, colIndex) => {
          // 特殊处理日期格式
          let value = cell.value;
          if (cell.value instanceof Date) {
            value = this.formatDate(cell.value);
          }
          
          rowData[headers[colIndex] = value?.toString() || '';
        });
        
        jsonData.push(rowData);
      });
      
      return jsonData;
    },
    
    // 日期格式化工具
    formatDate(date) {
      return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;
    }
  },
  
  data() {
    return {
      excelData: [] // 存储解析结果
    };
  }
}

结果:失败!worksheet.eachRow这行,报:eachRow是undefined!

方法三:EXCEL转JSON函数
EXCEL转JSON函数 excel json
结果:失败!包也是太大了,跟引用xlsx没区别

方法四:云开发
结果:应该是可以的,不过需要收费!

方法五:uniapp发行压缩代码
在这里插入图片描述
点击运行:

16:58:07.734 正在编译中...
16:58:24.208 项目  编译成功。前端运行日志,请另行在小程序开发工具的控制台查看。
16:58:24.208 正在启动微信开发者工具...
16:58:24.479 [微信小程序开发者工具] - initialize
16:58:24.482 [微信小程序开发者工具] ✖ IDE may already started at port 21765, trying to connect
16:58:26.403 [微信小程序开发者工具] ✔ IDE server started successfully, listening on http://127.0.0.1:32739
16:58:26.409 [微信小程序开发者工具] - open IDE
16:58:27.716 [微信小程序开发者工具] ✔ open IDE
16:58:27.736 微信开发者工具已启动,在HBuilderX中修改文件并保存,会自动刷新微信模拟器。
16:58:27.736 注:
16:58:27.736 1. 可以通过微信开发者工具切换pages.json中condition配置的页面,或者关闭微信开发者工具,然后再从HBuilderX中启动指定页面
16:58:27.736 2. 如果出现微信开发者工具启动后白屏的问题,检查是否启动多个微信开发者工具,如果是则关闭所有打开的微信开发者工具,然后再重新运行
16:58:27.736 3. 运行模式下不压缩代码且含有sourcemap,体积较大;若要正式发布,请点击发行菜单进行发布
16:58:27.736 运行方式:打开 微信开发者工具, 导入 dist/dev/mp-weixin 运行。

点击发行:

[HBuilder] 17:03:17.129 项目  [__UNI__40FC4BC] 开始发布到微信小程序...
[HBuilder] 17:03:18.334 小程序各家浏览器内核及自定义组件实现机制存在差异,可能存在样式布局兼容问题,参考:https://uniapp.dcloud.io/matter?id=mp
[HBuilder] 17:03:18.338 正在编译中...
[HBuilder] 17:03:42.492 项目 编译成功。前端运行日志,请另行在小程序开发工具的控制台查看。
[HBuilder] 17:03:42.542 项目 导出微信小程序成功,路径为:
[HBuilder] 17:03:42.544 正在启动微信开发者工具...
[HBuilder] 17:03:42.819 [微信小程序开发者工具] - initialize
[HBuilder] 17:03:42.836 [微信小程序开发者工具] ✔ IDE server has started, listening on http://127.0.0.1:32739
[HBuilder] 17:03:42.837 [微信小程序开发者工具] - open IDE
[HBuilder] 17:03:43.615 [微信小程序开发者工具] ✔ open IDE
[HBuilder] 17:03:43.620 请在微信小程序开发者工具中点击上传

然后在微信开发者工具点击上传即可!

结果:成功解决!我的理解是发行相当于build,不会把.sourcemap等文件打包,这样上传的时候代码体积就变小点!

注意:发行操作必须登录uniapp账号,顺便说一句,要保持manifest.json中的APPID一致,如果不一致,点击右侧重新获取一下即可
在这里插入图片描述

问题

1、atob is not defined

const binaryString = atob(fileData);
报错:atob is not defined

解决:使用uni-app自带的Base64转换API

const arrayBuffer = uni.base64ToArrayBuffer(fileData); // 返回ArrayBuffer
// 如果需要字符串,转换ArrayBuffer为字符串
const binaryString = Array.from(new Uint8Array(arrayBuffer))
  .map(byte => String.fromCharCode(byte))
  .join('');

2、uni.chooseFile微信端不支持,使用wx.chooseMessageFile
解决:
在这里插入图片描述

总结

1、引用大包时要么分包,要么使用uniapp的发行压缩代码再上传,还有就是引用云函数!

引用

uniapp打包微信小程序主包过大问题_uniapp 微信小程序时主包太大和vendor.js过大

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值