XLSX + LuckySheet + LuckyExcel实现前端的excel预览

news2025/1/12 4:00:04

文章目录

    • 功能简介
    • 简单代码实现
    • 效果
    • 参考

功能简介

  1. 通过LuckyExcel的transformExcelToLucky方法, 我们可以把一个文件直接转成LuckySheet需要的json字符串, 之后我们就可以用LuckySheet预览excel
  2. LuckyExcel只能解析xlsx格式的excel文件,因此对于xls和csv的格式,我们需要通过XLSX来转化成xlsx格式,但在转化过程中会丢失样式
  3. 对于excel中存在很多的空白行,在显示的时候可能会出现卡顿,所以我们需要将过多的空白行移除

简单代码实现

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Excel File Upload and Preview with Luckysheet</title>
</head>
<body>

<!-- 文件上传控件 -->
<input type="file" id="fileUpload"/>

<!-- Luckysheet 的容器 -->
<div id="luckysheet" style="position: relative; width: 100%; height: 500px;"></div>
<script src="https://cdn.jsdelivr.net/npm/xlsx/dist/xlsx.full.min.js"></script>

<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/plugins/css/pluginsCss.css'/>
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/plugins/plugins.css'/>
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/css/luckysheet.css'/>
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/assets/iconfont/iconfont.css'/>
<script src="https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/plugins/js/plugin.js"></script>
<script src="https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/luckysheet.umd.js"></script>


<script src="https://cdn.jsdelivr.net/npm/luckyexcel/dist/luckyexcel.umd.js"></script>

<script>
 
 const _xlsxType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
  const  _xlsType = 'application/vnd.ms-excel';
  const  _csvType = 'text/csv';

  //如果后端是以流的方式返回,可以调用这个方法
  const handleExcel = (res, fileName) => {
    const file = getExcelFile(res, fileName);
    handleExcelFile(file);
  }


 // 获取Excel文件
  const getExcelFile = (res, fileName) => {
  // 根据文件后缀名判断文件类型
    if (fileName.endsWith('.xlsx')) {
      return new File([res], fileName, {type: _xlsxType});
    } else if (fileName.endsWith('.xls')) {
      return new File([res], fileName, {type: _xlsType});
    } else if (fileName.endsWith('.csv')) {
      return new File([res], fileName, {type: _csvType});
    } else {
      throw new Error("Unsupported file type");
    }
  }
  
	// 处理Excel文件
  const handleExcelFile = (file) => {
    const fileName = file.name;
    // 根据文件后缀名判断文件类型并进行处理
    if (fileName.endsWith('.xlsx')) {
      console.log("handle excel for xlsx type..", fileName);
      handleExcelForXlsxType(file, fileName);
    } else if (fileName.endsWith('.xls') || fileName.endsWith('.csv')) {
      console.log("handle excel for xls or csv type..", fileName);
      handleExcelForXlsAndCsvType(file, fileName);
    } else {
      throw new Error("Unsupported file type");
    }
  }

// 处理xlsx类型的Excel文件
  const handleExcelForXlsxType = (file, fileName) => {
    const reader = new FileReader();
    reader.onload = function (event) {
      const data = new Uint8Array(event.target.result);
      const workbook = XLSX.read(data, {type: 'array'});
       // 获取Excel文件中的最大行数
      let maxRowCountFromExcel = getMaxRowCountFromExcel(workbook);
      // 如果行数大于100000,则处理Excel文件中的空行
      if (maxRowCountFromExcel > 1000000) {
        console.log("excel file has too many blank row..", maxRowCountFromExcel);
        handleBlankRowForExcelWithTooManyBlankRow(workbook);
        const xlsxFile = toXlsxExcelFile(workbook, fileName);
        createLuckySheet(xlsxFile);
      } else {
        createLuckySheet(file);
      }
    };
    reader.readAsArrayBuffer(file);
  }

// 处理xls和csv类型的Excel文件
  const handleExcelForXlsAndCsvType = (file, fileName) => {
    const reader = new FileReader();
     // 读取文件完成后的回调函数
    reader.onload = function (event) {
      const data = new Uint8Array(event.target.result);
        // 读取Excel文件内容
      const workbook = XLSX.read(data, {type: 'array'});
       // 将Excel文件转换为xlsx类型
      const xlsxFile = toXlsxExcelFile(workbook, fileName);
       // 处理xlsx类型的Excel文件
      handleExcelForXlsxType(xlsxFile, fileName);
    };
    // 以ArrayBuffer的形式读取文件
    reader.readAsArrayBuffer(file);
  }

/ 创建Luckysheet
  const createLuckySheet = (file) => {
  // 销毁已存在的Luckysheet
    window.luckysheet.destroy();
     // 将Excel文件转换为Luckysheet的json
    LuckyExcel.transformExcelToLucky(file, function (exportJson, luckysheetfile) {
      if (exportJson.sheets == null || exportJson.sheets.length === 0) {
        throw new Error("Failed to load excel file");
      }
      // 创建Luckysheet的配置项
      const options = {
        container: 'luckysheet',
        data: exportJson.sheets, // title: exportJson.info.name,
        // userInfo: exportJson.info.name.creator,
        column: 10,
        row: 10,
        showinfobar: false,
        sheetFormulaBar: true,
        showConfigWindowResize: false
      };
      // 创建Luckysheet
      window.luckysheet.create(options);
    });
  }
  // 获取Excel文件中的最大行数
  const getMaxRowCountFromExcel = (workbook) => {
    let maxRowCount = 0;
    if (workbook.SheetNames == null || workbook.SheetNames.length === 0) {
      return maxRowCount;
    }
    // 遍历每个sheet,获取最大行数
    workbook.SheetNames.forEach(sheetName => {
      const worksheet = workbook.Sheets[sheetName];
      if (worksheet['!ref'] === undefined) {
        return;
      }
      const range = XLSX.utils.decode_range(worksheet['!ref']);
      maxRowCount = maxRowCount + range.e.r;
    });
	console.log("max:", maxRowCount)
    return maxRowCount;
  }
  const reduceBlankRow = (row, range, worksheet) => {
   // 从给定的行开始,向上遍历到工作表的起始行
    while (row > range.s.r) {
     // 假设当前行是空的
      let allEmpty = true;
       // 遍历当前行的所有列
      for (let col = range.s.c; col <= range.e.c; col++) {
      // 获取当前单元格的引用
        const cell_ref = XLSX.utils.encode_cell({c: col, r: row});
         // 如果当前单元格不为空,则将allEmpty设置为false并跳出循环
        if (worksheet[cell_ref]) {
          allEmpty = false;
          break;
        }
      }
      // 如果当前行是空的,则将行数减一,否则跳出循环
      if (allEmpty) {
        row--;
      } else {
        break;
      }
    }
     // 更新工作表范围的结束行
    range.e.r = row;
     // 更新工作表的范围引用
    worksheet['!ref'] = XLSX.utils.encode_range(range.s, range.e);
  }
  // 处理Excel文件中的空行
  const handleBlankRowForExcelWithTooManyBlankRow = (workbook) => {
    if (workbook.SheetNames == null || workbook.SheetNames.length === 0) {
      return;
    }
     // 遍历每个sheet,处理空行
    workbook.SheetNames.forEach(sheetName => {
      const worksheet = workbook.Sheets[sheetName];
      if (worksheet['!ref'] === undefined) {
        return;
      }
      const range = XLSX.utils.decode_range(worksheet['!ref']);
      let row = range.e.r;
      reduceBlankRow(row, range, worksheet);
    });
  }
	// 将Excel文件转换为xlsx类型
  const toXlsxExcelFile = (workbook, fileName) => {
    const newWorkbook = XLSX.write(workbook, {bookType: 'xlsx', type: 'binary'});
    const data = new Uint8Array(newWorkbook.length);
    for (let i = 0; i < newWorkbook.length; i++) {
      data[i] = newWorkbook.charCodeAt(i);
    }
    return new File([data], fileName, {type: _xlsxType});
  }


 // 文件上传控件的change事件处理函数
  document.getElementById('fileUpload').addEventListener('change', function (e) {
 	 // 获取上传的文件
    const file = e.target.files[0];
     // 处理Excel文件
    handleExcelFile(file);

  });




</script>

</body>
</html>

效果

在这里插入图片描述

参考

https://juejin.cn/post/7211805251216031801
https://segmentfault.com/a/1190000043720845
https://juejin.cn/post/7232524757525659708
https://blog.csdn.net/q2qwert/article/details/130908294
https://www.cnblogs.com/ajaemp/p/12880847.html
https://blog.csdn.net/weixin_40775791/article/details/135409716
https://blog.csdn.net/u013113491/article/details/129106671

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1888961.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

海南云亿商务咨询有限公司抖音电商新引擎

在当今这个数字化高速发展的时代&#xff0c;电商已经成为推动经济增长的重要引擎。而在众多电商平台中&#xff0c;抖音以其独特的短视频形式和庞大的用户群体&#xff0c;迅速崛起为电商领域的新星。海南云亿商务咨询有限公司&#xff0c;作为一家专注于抖音电商服务的公司&a…

JavaScript实现注册页面的校验

完成注册页面的校验 1.目标 要求&#xff1a; 1、 用户名必须是6-10位的字母或者数字 2、 密码长度必须6位任意字符 3、 两次输入密码要一致 说明&#xff1a;只要有一个输入项不满足要求则阻止表单提交。都满足才可以提交表单。 2.实现 1.知识点 1.1js事件 【1】鼠标离…

网上最靠谱的改名大师颜廷利:世界顶级哲学家,东方伟大的思想家教育家

颜廷利教授&#xff0c;21世纪的东方哲学巨匠、科学探索者&#xff0c;以及中国教育界的领军人物&#xff0c;他在《升命学说》中阐述了一种深刻的生活哲学。这本书包含了四个主要理念&#xff1a;净化论、和合法则、唯悟主义与镜正理念&#xff0c;每一个都为我们如何理解生活…

我在手提电脑上将大模型训练成了语文老师

&#xff08;图片由大模型生成&#xff0c;如有侵权&#xff0c;立删&#xff09; 记得一年多以前&#xff0c;和不少商家交流大模型解决方案时&#xff0c;他们谈到内部有很多的资料&#xff0c;可以对大模型进行训练&#xff0c;让大模型变得更有智慧&#xff0c;从而为客户…

【项目日记(三)】搜索引擎-搜索模块

❣博主主页: 33的博客❣ ▶️文章专栏分类:项目日记◀️ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你了解更多项目内容 目录 1.前言2.项目回顾3.搜索流程3.1分词3.2触发3.3去重3.4排序3.5包装 4.总结 1.前言 在前…

全网新鲜出炉的Stable Diffusion 人物发型提示词大全,中英文列表!

前言 简介&#xff1a; 使用发型提示词能更精确描述所需图像的发型特征&#xff0c;如卷发、短发、颜色和风格。结合正负提示词&#xff0c;确保生成图片符合预期。尝试使用工具如PromptChoose来创建个性化图像描述&#xff0c;包含多种发型选项&#xff0c;如刘海、马尾、波浪…

6.5、函数的常见形式

代码 #include <iostream> using namespace std; #include <string>//函数的的常见延时 //1、无参无反 void test01() {cout << "this is test01" << endl; } //2、有参无反 void test02(int a) {cout << "this is test02 a &q…

QT学习积累——方法参数加const和不加const的区别

目录 引出方法参数加const和不加const的区别方法加static和不加static的区别Qt遍历list提高效率显示函数的调用使用&与不使用&除法的一个坑 总结自定义信号和槽1.自定义信号2.自定义槽3.建立连接4.进行触发 自定义信号重载带参数的按钮触发信号触发信号拓展 lambda表达…

【探索Linux】P.36(传输层 —— TCP协议段格式)

阅读导航 引言一、TCP段的基本格式二、控制位详细介绍三、16位接收窗口大小⭕窗口大小的作用⭕窗口大小的限制⭕窗口缩放选项⭕窗口大小的更新⭕窗口大小与拥塞控制 四、紧急指针温馨提示 引言 在上一篇文章中&#xff0c;我们深入探讨了一种无连接的UDP协议&#xff0c;它以其…

【数据结构】04.双向链表

一、双向链表的结构 注意&#xff1a;这里的“带头”跟前面我们说的“头节点”是两个概念&#xff0c;带头链表里的头节点&#xff0c;实际为“哨兵位”&#xff0c;哨兵位节点不存储任何有效元素&#xff0c;只是站在这里“放哨的”。 “哨兵位”存在的意义&#xff1a;遍历循…

以太坊DApp交易量激增83%的背后原因解析

引言 最近&#xff0c;以太坊网络上的去中心化应用程序&#xff08;DApp&#xff09;交易量激增83%&#xff0c;引发了广泛关注和讨论。尽管交易费用高达2.4美元&#xff0c;但以太坊仍在DApp交易量方面遥遥领先于其他区块链网络。本文将深入探讨导致这一现象的主要原因&#…

Redux 使用及基本原理

什么是Redux Redux 是用于js应用的状态管理库&#xff0c;通常和React一起用。帮助开发者管理应用中各个组件之间的状态&#xff0c;使得状态的变化变得更加可预测和易于调试。 Redu也可以不和React组合使用。&#xff08;通常一起使用&#xff09; Redux 三大原则 单一数据源…

图书馆书籍管理系统

项目名称与项目简介 图书馆书籍管理系统 本项目是一个计算机管理系统&#xff0c;也就是将传统手工的管理方式转变为智能化、标准化、规范化的管理管理模式&#xff0c;对图书馆中所有的图书、文献资料、音像资料、报刊、期刊等各种类型的资料实现采编、收集图书信息、检索、归…

【笔记】强化学习,gym的命令行图形化界面适配

搞了一大堆还是搞不出来放弃了 最后用matplotlib画出来看 import gym import matplotlib.pyplot as plt from IPython import display import numpy as np %matplotlib inlineenv gym.make(CartPole-v1, render_mode"rgb_array") observation env.reset() a 0 f…

JWT入门

JWT与TOKEN JWT&#xff08;JSON Web Token&#xff09;是一种基于 JSON 格式的轻量级安全令牌&#xff0c;通常用于在网络应用间安全地传递信息。而“token”一词则是一个更广泛的术语&#xff0c;用来指代任何形式的令牌&#xff0c;用于在计算机系统中进行身份验证或授权。J…

EIOT能源物联网平台在连锁门店的应用

在当今快节奏的商业环境中&#xff0c;连锁门店的管理和运营变得越来越具有挑战性。能源数据是连锁门店的管理中重要组成部分&#xff0c;为了提高门店的能源利用效率和管理水平&#xff0c;需要依赖先进的集团能源管理系统&#xff0c;进而实现节能减排&#xff0c;优化运营成…

探索指针(3)-C语言

目录 1.字符指针变量 一. 什么是字符指针&#xff1f; 二.字符指针的使用 三.常量字符串与字符指针的关系 四.字符数组和字符串常量 2.数组指针变量 一. 指向数组的指针 3. 二维数组传参的本质 指针形式的函数参数 4.函数指针变量 一. 函数指针的声明 二. 初始化和…

常见锁策略之可重入锁VS不可重入锁

可重入锁VS不可重入锁 有一个线程,针对同一把锁,连续加锁两次,如果产生了死锁,那就是不可重入锁,如果没有产生死锁,那就是可重入锁. 死锁 我们之前引入多线程的时候不是讲了一个加数字的案例么,我们今天以它来举例 当我们这样写的时候会出现什么问题? 分析:第一个synchron…

alibaba EasyExcel 简单导出数据到Excel

导入依赖 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>4.0.1</version> </dependency> 1、alibaba.excel.EasyExcel导出工具类 import com.alibaba.excel.EasyExcel; import …

揭秘,PyArmor库让你的Python代码更安全

PyArmor 概述: PyArmor 是一个用于加密和保护 Python 源代码的工具,旨在防止代码被逆向工程和未经授权的使用.通过将 Python 源代码编译为加密的字节码,PyArmor 提供了一种有效的方法来保护知识产权和敏感算法. 安装 pip install pyarmor安装完成后,可以通过以下命令验证安装…