vue3项目中本地引入LuckySheet实现Excel在线编辑、本地导入与导出

vue3项目中通过LuckySheet实现Excel在线编辑、本地导入与导出

一、集成LuckySheet

集成方式有CDN引入和本地引入两种,我采用的是本地引入。参考文章:https://blog.csdn.net/m0_59415345/article/details/136963918

二、实现本地自动导入Excel

因为我的业务要求用户在上一个界面点击编辑后自动跳转LuckySheet在线编辑界面,所以文件上传方式和参考文章实现的方式不太相同。
我的项目中通过上一个界面路由query传递文件的路径path参数(http或者https开头)到onlineEdit.vue,在LuckySheet初始化完成后通过JavaScript触发input按钮的文件选择并模拟文件输入变化,以编程方式设置文件并触发change事件。

1、先安装LuckyExcel依赖

npm install luckyexcel --save

2、vue组件代码如下

<template>
  <div className="hello">
    <div style="position: absolute; top: 0">
      <input ref="fileInput" style="font-size: 16px; width: 400px" type="file" @change="uploadExcel" disabled />
    </div>
    <div id="luckysheet" style="margin: 0px; padding: 0px; position: absolute; width: 100%; left: 0px; top: 30px; bottom: 0px"></div>
  </div>
</template>
<script>
  import LuckyExcel from 'luckyexcel';
  import { getFileAccessHttpUrl } from '@/utils/common/compUtils';

  export default {
    props: {
      msg: String,
    },
    data() {
      return {
        selected: '',
        isMaskShow: false,
      };
    },
    async mounted() {
      // 初始化Luckysheet的空表格
      this.initLuckySheet();
      // 从路由参数获取文件路径
      let filePath = getFileAccessHttpUrl(this.$route.query.path);
      if (filePath) {
        try {
          // 自动加载文件
          await this.loadFileAutomatically(filePath);
        } catch (error) {
          alert('自动加载文件失败,请检查文件路径是否正确。');
        }
      }
    },
    methods: {
      initLuckySheet() {
        this.$nextTick(() => {
          $(function () {
            luckysheet.create({
              // 保持原来的初始化配置
              container: 'luckysheet',
              title: 'Luckysheet De1mo',
              lang: 'zh',
              plugins: ['chart'],
            });
          });
        });
      },
      async loadFileAutomatically(filePath) {
        try {
          if (!filePath.startsWith('http')) {
            throw new Error('仅支持 HTTP/HTTPS 协议');
          }

          // 处理特殊字符编码
          const encodedFilePath = encodeURI(filePath);
          const response = await fetch(encodedFilePath);
          if (!response.ok) {
            throw new Error(`文件下载失败: ${response.status} ${response.statusText}`);
          }

          // 校验文件扩展名
          const fileName = decodeURIComponent(
            // 解码中文文件名
            encodedFilePath.split('/').pop() || 'file.xlsx'
          );
          const fileExt = fileName.split('.').pop().toLowerCase();
          if (fileExt !== 'xlsx') {
            throw new Error('仅支持 .xlsx 文件');
          }

          // 强制修正 MIME 类型
          const blob = await response.blob();
          const fixedBlob = new Blob([blob], {
            type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
          });

          // 创建 File 对象
          const file = new File([fixedBlob], fileName);

          // 触发文件选择
          const input = this.$refs.fileInput;
          const dataTransfer = new DataTransfer();
          dataTransfer.items.add(file);
          input.files = dataTransfer.files;
          input.dispatchEvent(new Event('change'));
        } catch (error) {
          console.error('自动加载失败:', error);
          alert(`错误: ${error.message}`);
        }
      },
      uploadExcel(evt) {
        // 保持原有的上传处理逻辑
        const files = evt.target.files;
        if (!files || files.length === 0) {
          alert('请选择文件');
          return;
        }

        // 验证文件类型
        const file = files[0];
        if (!file.name.endsWith('.xlsx')) {
          alert('仅支持.xlsx文件');
          return;
        }

        // 转换并加载表格
        LuckyExcel.transformExcelToLucky(file, (exportJson) => {
          if (!exportJson.sheets) {
            alert('文件解析失败');
            return;
          }
          window.luckysheet.destroy();
          window.luckysheet.create({
            container: 'luckysheet',
            showinfobar: false,
            data: exportJson.sheets,
            title: exportJson.info.name,
          });
        });
      },
    },
  };
</script>

其中getFileAccessHttpUrl函数如下,主要作用是将文件路径转换为完整的静态资源HTTP访问URL

export const getFileAccessHttpUrl = (fileUrl, prefix = 'http') => {
  let result = fileUrl;
  try {
    if (fileUrl && fileUrl.length > 0 && !fileUrl.startsWith(prefix)) {
      //判断是否是数组格式
      let isArray = fileUrl.indexOf('[') != -1;
      if (!isArray) {
        let prefix = `${baseApiUrl}/x/x/x/`;  //这里替换成自己的后端文件下载api
        // 判断是否已包含前缀
        if (!fileUrl.startsWith(prefix)) {
          result = `${prefix}${fileUrl}`;
        }
      }
    }
  } catch (err) {}
  return result;
};

三、导出Excel

导出文件就比较简单,用的LuckySheet官方函数,跟开头提到的参考文章实现逻辑一致
1、先安装依赖

npm i exceljs --save
npm i file-saver --save

2、新建export.js函数(我的代码做了一点点修改,可以直接复制参考文章的使用)

在这里插入图片描述

整体onlineEdit.vue组件代码如下:

<template>
  <div className="hello">
    <div style="position: absolute; top: 0">
      <input ref="fileInput" style="font-size: 16px; width: 400px" type="file" @change="uploadExcel" disabled />
      <a-button @click="saveHandle(e)">保存</a-button>
    </div>
    <div id="luckysheet" style="margin: 0px; padding: 0px; position: absolute; width: 100%; left: 0px; top: 30px; bottom: 0px"></div>
  </div>
</template>

<script>
  import LuckyExcel from 'luckyexcel';
  import { exportExcel } from './export';
  import { getFileAccessHttpUrl } from '@/utils/common/compUtils';

  export default {
    props: {
      msg: String,
    },
    data() {
      return {
        selected: '',
        isMaskShow: false,
      };
    },
    async mounted() {
      // 初始化Luckysheet的空表格
      this.initLuckySheet();
      // 从路由参数获取文件路径
      let filePath = getFileAccessHttpUrl(this.$route.query.path);
      console.log('this is path', filePath);
      if (filePath) {
        try {
          // 自动加载文件
          await this.loadFileAutomatically(filePath);
        } catch (error) {
          alert('自动加载文件失败,请检查文件路径是否正确。');
        }
      }
    },
    methods: {
      initLuckySheet() {
        this.$nextTick(() => {
          $(function () {
            luckysheet.create({
              // 保持原来的初始化配置
              container: 'luckysheet',
              title: 'Luckysheet De1mo',
              lang: 'zh',
              plugins: ['chart'],
            });
          });
        });
      },
      async loadFileAutomatically(filePath) {
        try {
          if (!filePath.startsWith('http')) {
            throw new Error('仅支持 HTTP/HTTPS 协议');
          }

          // 处理特殊字符编码
          const encodedFilePath = encodeURI(filePath);
          const response = await fetch(encodedFilePath);
          if (!response.ok) {
            throw new Error(`文件下载失败: ${response.status} ${response.statusText}`);
          }

          // 校验文件扩展名
          const fileName = decodeURIComponent(
            // 解码中文文件名
            encodedFilePath.split('/').pop() || 'file.xlsx'
          );
          const fileExt = fileName.split('.').pop().toLowerCase();
          if (fileExt !== 'xlsx') {
            throw new Error('仅支持 .xlsx 文件');
          }

          // 强制修正 MIME 类型
          const blob = await response.blob();
          const fixedBlob = new Blob([blob], {
            type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
          });

          // 创建 File 对象
          const file = new File([fixedBlob], fileName);

          // 触发文件选择
          const input = this.$refs.fileInput;
          const dataTransfer = new DataTransfer();
          dataTransfer.items.add(file);
          input.files = dataTransfer.files;
          input.dispatchEvent(new Event('change'));
        } catch (error) {
          console.error('自动加载失败:', error);
          alert(`错误: ${error.message}`);
        }
      },
      uploadExcel(evt) {
        // 保持原有的上传处理逻辑
        const files = evt.target.files;
        if (!files || files.length === 0) {
          alert('请选择文件');
          return;
        }

        // 验证文件类型
        const file = files[0];
        if (!file.name.endsWith('.xlsx')) {
          alert('仅支持.xlsx文件');
          return;
        }

        // 转换并加载表格
        LuckyExcel.transformExcelToLucky(file, (exportJson) => {
          if (!exportJson.sheets) {
            alert('文件解析失败');
            return;
          }
          window.luckysheet.destroy();
          window.luckysheet.create({
            container: 'luckysheet',
            showinfobar: false,
            data: exportJson.sheets,
            title: exportJson.info.name,
          });
        });
      },
      saveHandle() {
        try {
          // 获取所有工作表数据(注意这里要使用正确的API)
          const sheets = window.luckysheet.getAllSheets();
          // console.log('this is content:', sheets);
          // 调用导出方法(假设value参数是文件名)
          const defaultName = sheets[0]?.name || 'export';
          exportExcel(sheets, defaultName);

          this.$message.success('保存成功');
        } catch (error) {
          console.error('保存失败:', error);
          this.$message.error('保存失败,请检查控制台');
        }
      },
    },
  };
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值