vue3集成LuckySheet实现导入本地Excel进行在线编辑

news2024/11/15 15:45:32

第一步:克隆或者下载下面的代码

git clone https://github.com/dream-num/Luckysheet.git

第二步:安装依赖

npm install
npm install gulp -g  

第三步:运行

npm run dev

效果如下图所示
在这里插入图片描述
第四步:打包
打包执行成功后,在文件夹目录下会出现dis文件夹,如下图所示:

npm run build

在这里插入图片描述
第五步:本地引入

把dist文件夹中的代码全部复制粘贴到你项目的public文件夹中,index.html文件除外。

在你项目的index.html文件中引入如下代码,如果你复制的位置是其他地方,需要用绝对路径引入这些文件。
<link rel='stylesheet' href='./public/plugins/css/pluginsCss.css' />
<link rel='stylesheet' href='./public/plugins/plugins.css' />
<link rel='stylesheet' href='./public/css/luckysheet.css' />
<link rel='stylesheet' href='./public/assets/iconfont/iconfont.css' />
<script src="./public/plugins/js/plugin.js"></script>
<script src="./public/luckysheet.umd.js"></script>		

接下来就是在项目中使用这个插件
首先要引入luckyexcel 的依赖,我们导入导出本地excel会用到

 npm install luckyexcel --save
 如果引入依赖报错可能是依赖冲突,可以使用下面的
 npm install luckyexcel --save --force

然后创建一个vue页面文件

<template>
  <div>
    <div style="height: 10px;position: absolute">
      <el-upload
          ref="upload"
          class="upload-demo"
          action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
          :limit="1"
          :on-change="handleFileChange"
          :auto-upload="false"
          accept=".xlsx"
      >
        <template #trigger>
          <el-button type="primary">select file</el-button>
        </template>
      </el-upload>
    </div>
    <div v-if="isShow" id="luckysheet" class="luckysheet-wrap"></div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import LuckyExcel from 'luckyexcel';
import {ElMessage} from "element-plus";

const isShow = ref(false)

function handleFileChange(file, newFileList) {
  const selectedFile = file.raw;
  if (!(selectedFile instanceof File)) {
    console.error('传入了非文件对象');
    return;
  }

  if (selectedFile.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') {
    console.log('文件是xlsx类型');
  } else {
    console.error('不是xlsx文件');
    ElMessage.error('请选择xlsx类型文件')
    return;
  }

  let filename = selectedFile.name.replace(/\.[^/.]+$/, ""); // 去除文件扩展名
  let reader = new FileReader();

  reader.onload = async (e) => {
    let fileData = e.target.result;
    try {
      isShow.value = true
      LuckyExcel.transformExcelToLucky(fileData, async (exportJson, luckysheetfile) => {
        console.log(exportJson.sheets)
        creatExcel(filename, JSON.stringify(exportJson.sheets))
      });
    } catch (e) {
      console.error(e);
    }
  };

  reader.onerror = function() {
    console.error("File could not be read! Code " + reader.error.code);
  };

  reader.readAsArrayBuffer(selectedFile);
}

function creatExcel(title, content){
  const options = {
    container: 'luckysheet', // 设定DOM容器的id
    title: 'excel 表格', // 设定表格名称
    lang: 'zh', // 设定表格语言
    hook: {
      updated: (e) => {
        //监听更新,并在1s后自动保存
        $('#luckysheet_info_detail_save').text("已修改")
        let title = $('#luckysheet_info_detail_input').val();
        let content = luckysheet.getAllSheets();
        //去除临时数据,减小体积
        for (let i in content)
          content[i].data = undefined
        console.log(title)
        console.log(content)
      }
    },

  }
  options.data = JSON.parse(content)
  options.title = title;

  window.luckysheet.create(options)
}

onMounted(() => {
  
});
</script>

<style scoped>
.luckysheet-wrap {
  margin: 0px;
  padding: 0px;
  position: absolute;
  width: 100%;
  height: 100%;
  left: 0px;
  top: 0px;
}
</style>


在这里插入图片描述
点击按钮选择一个xlsx文件就能导入成功了,效果如下(这里只能导入xlsx文件,导入xls文件会报错,暂时不知道什么原因,如果有xls文件的话可以把表格另存为xlsx类型的文件再导入)
在这里插入图片描述
下面放一个完整的demo展示效果

<template>
  <div style="width: 100%; height: 100vh;overflow: auto;">
    <div>
      <div style="display: flex;">
        <div style="margin-right: 10px;">
          <el-upload ref="upload" :auto-upload="false" accept=".xlsx" :show-file-list='false' :on-change="handleChangeUpload"
                     action="#" class="upload-demo" multiple>
            <el-button type="primary">导入</el-button>
          </el-upload>
        </div>
        <el-button type="primary" @click="goBack()">返回</el-button>
      </div>
    </div>
    <span>电源配线图</span>
    <el-table :data="dataList" width="100%" border :max-height="750">
      <el-table-column label="序号" align="center" key="id" prop="id" fixed width="100px" />
      <el-table-column label="模板名称" align="left" key="name" prop="name"/>
      <el-table-column label="导入时间" align="center" key="addTime" prop="addTime"/>
      <el-table-column label="编辑时间" align="center" key="upTime" prop="upTime"/>
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right">
        <template #default="scope">
          <el-button link type="primary" icon="Edit" @click="updateData(scope.row)">编辑</el-button>
          <el-button link type="primary" icon="Delete" @click="deleteData(scope.row)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>

    <pagination
        v-show="total > 0"
        :total="total"
        v-model:page="pageNum"
        v-model:limit="pageSize"
        @pagination="getDataList"
        :page-sizes="[5, 10, 20, 50]"
    />
  </div>
</template>

<script setup>

import {onBeforeUnmount, ref} from "vue";
import {ElMessage} from "element-plus";
import {closeWindow, openCenteredWindow, verifyCommand} from "../../openWindow";
import {useRouter} from "vue-router";
import {deletePower, importPower, selectPowerList} from "../../../../api/draw/power";
import LuckyExcel from 'luckyexcel';

const {proxy} = getCurrentInstance();
const router = useRouter();

const dataList = ref([])

const total = ref(0)
const pageNum = ref(1)
const pageSize = ref(10)

//查询数据
function getDataList(){
  selectPowerList({
    pageNum: pageNum.value,
    pageSize: pageSize.value
  }).then(result => {
    dataList.value = result.rows
    total.value = result.total
  })
}

//删除数据
async function deleteData(row){
  if ( await verifyCommand() ){
    proxy.$confirm('确定删除吗?', '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    }).then(() => {
      let data = {
        id: row.id,
      }
      deletePower(data).then(res=>{
        if (res.code === 200){
          getDataList()
          ElMessage.success('删除成功!');
        }else {
          ElMessage.error('删除失败')
        }
      })
    }).catch(() => {
      proxy.$message({
        type: 'info',
        message: '取消删除'
      });
    });
  }
}

//编辑按钮
function updateData(row){
  router.push({
    name: 'excel',
    state: {
      id: row.id,
      title: row.name,
      content: row.content,
    }
  });
}

function handleChangeUpload(file) {
  const selectedFile = file.raw;
  if (!(selectedFile instanceof File)) {
    console.error('传入了非文件对象');
    return;
  }

  if (selectedFile.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') {
    console.log('文件是xlsx类型');
  } else {
    console.error('不是xlsx文件');
    ElMessage.error('请选择xlsx类型文件')
    return;
  }

  let filename = selectedFile.name.replace(/\.[^/.]+$/, ""); // 去除文件扩展名
  let reader = new FileReader();

  reader.onload = async (e) => {
    let fileData = e.target.result;
    try {
      LuckyExcel.transformExcelToLucky(fileData, async (exportJson, luckysheetfile) => {
        console.log(exportJson.sheets)
        //更改配置中的行数为当前最大行
        //exportJson.sheets[0].config.rowlen = exportJson.sheets[0].celldata[exportJson.sheets[0].celldata.length-1].r+2
        let data = {
          name: filename,
          content: JSON.stringify(exportJson.sheets)
        }
        importPower(data).then(res=>{
          if (res.code === 200){
            getDataList()
            ElMessage.success('导入成功')
          }else {
            ElMessage.error(res.msg)
          }
        })
      });
    } catch (e) {
      console.error(e);
    }
  };

  reader.onerror = function() {
    console.error("File could not be read! Code " + reader.error.code);
  };

  reader.readAsArrayBuffer(selectedFile);
}

onBeforeUnmount (() => {
  closeWindow();
});

// 监听页面即将刷新的事件
window.addEventListener('beforeunload', function (event) {
  closeWindow();
});

const goBack = () => {
  router.go(-1); // 返回上一页
};

getDataList();
</script>

<style scoped>

</style>

在这里插入图片描述

<template>
  <div>
    <div id="luckysheet" class="luckysheet-wrap"></div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import {ElMessage} from "element-plus";
import {updatePower} from "../../../api/draw/power";

onMounted(() => {
  setExcelData();
  setExcelStyle();
});

//对表格数据进行渲染
function setExcelData(){
  let title = history.state.title;
  let content = history.state.content;
  const options = {
    container: 'luckysheet', // 设定DOM容器的id
    title: 'excel 表格', // 设定表格名称
    lang: 'zh', // 设定表格语言
    hook: {
      updated: (e) => {
        //监听更新,并在1s后自动保存
        $('#luckysheet_info_detail_save').text("已修改")
        let title = $('#luckysheet_info_detail_input').val();
        let content = luckysheet.getAllSheets();
        //去除临时数据,减小体积
        for (let i in content)
          content[i].data = undefined
      }
    },
  }
  options.data = JSON.parse(content)
  options.title = title;
  window.luckysheet.create(options)
}

//对默认表格的样式进行修改
function setExcelStyle(){
  //去除左上角logo
  let leftLogo = document.querySelector('.luckysheet-share-logo');
  leftLogo.className = '';
  //去除左上角返回按钮
  let leftButton = document.getElementById('luckysheet_info_detail_title');
  leftButton.remove();

  // 创建一个新的保存按钮
  let newDiv = document.createElement('div');
  newDiv.innerHTML = '保存';
  newDiv.style.cursor = 'pointer'
  newDiv.addEventListener('click', function() {
    saveData();
  });
  let firstChild = document.querySelector('#luckysheet_info_detail').firstElementChild;
  document.querySelector('#luckysheet_info_detail').insertBefore(newDiv, firstChild);
}

//保存数据
function saveData(){
  let title = $('#luckysheet_info_detail_input').val();
  let content = luckysheet.getAllSheets();
  //去除临时数据,减小体积
  for (let i in content)
    content[i].data = undefined
  //更改配置中的行数为当前最大行
  content[0].config.rowlen = content[0].celldata[content[0].celldata.length-1].r+2
  let id = history.state.id
  let data = {
    id: id,
    name: title,
    content: JSON.stringify(content)
  }
  updatePower(data).then(res=>{
    if (res.code === 200){
      history.state.title = title;
      history.state.content = JSON.stringify(content);
      ElMessage.success('保存成功!');
    }else {
      ElMessage.error('保存失败')
    }
  })
}
</script>

<style scoped>
.luckysheet-wrap {
  margin: 0px;
  padding: 0px;
  position: absolute;
  width: 100%;
  height: 100%;
  left: 0px;
  top: 0px;
}
</style>

在这里插入图片描述

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

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

相关文章

40 元组与列表的异同点

① 列表和元组都属于有序序列&#xff0c;都支持双向索引访问其中的元素&#xff0c; 以及使用 count() 方法统计元素的出现次数和 index() 方法获取元素的索引&#xff0c;len()、map()、filter()等大量内置函数和 、*、、in 等运算符也都可以作用于列表和元组。虽然列表和元组…

互联网扭蛋机小程序,行业的发展前景

近年来&#xff0c;扭蛋机在市场上的影响力逐渐增加&#xff0c;受到了消费者的欢迎&#xff0c;发展前景非常广阔。目前&#xff0c;扭蛋机市场迎来了线上发展趋势&#xff0c;消费者也开始热衷于在线上参与扭蛋&#xff01;扭蛋机小程序的发展&#xff0c;也为行业带来了更大…

comfyui安装的报错:cuda driver easyphoto的报错坑:ONNXRuntimeError FAIL

。。。。怎么说呢。。。。坑 安装comfyui的时候&#xff0c;comfyui默认的是最新版的torch 2.5.1版本 跟我本地的cuda版本根本不匹配 于是就爆出了cuda driver不匹配&#xff0c;要升级 同事升级cuda驱动之后。。。系统整个崩了 行吧&#xff0c;花了几个小时&#xff0c;才知道…

Web框架:Django基础(1)

文章目录 Web框架&#xff1a;Django基础1.web框架底层1.1 网络通信1.2 常见软件架构1.3 手撸web框架1.4 告诉你两个关键点&#xff1a;短连接长连接 2.web框架网络通信的基本流程2.1 wsgiref2.2 werkzeug2.3 各框架的区别 小结3.快速上手django框架3.1 安装3.2 命令行3.3 Pych…

【分布式】分库分表知识点大全

为什么要分库分表 随着业务量的增加导致数据库中数据量的增加&#xff0c;可能拖慢查询的性能&#xff0c;影响业务的可用性&#xff1b;如果数据库采用读写分离&#xff0c;可能会导致从库的延迟较大&#xff0c;主库进行写操作后&#xff0c;从库因为延迟无法及时同步&#…

基于RK3588+YOLO模型打造稳固型电力巡检机器人控制器

创新打造电力巡检机器人用计算机产品方案 目前&#xff0c;智能电网建设和增强供电可靠性已上升到国家战略&#xff0c;使得我国基数庞大的电力设备的监测、运维等需求充分释放&#xff0c;变电站/配电站巡检机器人市场需求高涨。 1、电力巡检机器人的市场优势 电力系统智能巡…

MySQL的索引与SQL优化

索引 官方的定义索引是一种数据结构,从生活维度讲,假如将一本书看成是一张表, 这本书的目录就是表中的索引(Index).在数据库中数据量比较大时,为了快速找到们需要的数据可以使用索引,这样可以提高查询的效率,开发过程中,如果发现查询时频繁使用到的字段,也可以添加索引进行优化…

苹果手机相片删除了怎么恢复回来?4个妙计,任你选择

使用iPhone的用户们&#xff0c;是否曾因手误或其他原因不小心删除了重要的相片&#xff0c;不知道如何找回而手足无措&#xff1f;别急&#xff0c;这里有高效的解决方案等你来挑选。本文将直接切入主题&#xff0c;为你提供4种实用的解决苹果手机相片删除了怎么恢复回来的小妙…

2024杭电多校01——1003树

补题链接 官方题解 补充: ( ∑ u ∈ t r e e i a u ) 2 (\sum_{u \in tree_i} a_u)^2 (∑u∈treei​​au​)2 ∑ u ∈ t r e e i a u 2 2 ∑ x ∈ t r e e i , y ∈ t r e e i a x ∗ a y \sum_{u \in tree_i} a_u^{2}2\sum_{x \in tree_i,y \in tree_i} a_x*a_y ∑u∈t…

Prompt——3分钟掌握,润色论文的7条经典指令。帮助很大,一定要看!

这是一篇帮助你润色论文的ChatGPT指令合集&#xff0c;整理了润色过程中语法优化、审阅校对、专业风格等7个主要方面。 建议收藏&#xff0c;需要的时候直接CtrlV即可&#xff0c;一定对你科研有所帮助~ 1. 修复语法和句法 第一个提示是修复语法和句法。这是任何写作的关键部…

vue页面左右箭头手动切换中间app列表

1 效果: 2 HTML代码分析: HTML代码: <div class"all_app"><div class"app-container"><el-button icon"el-icon-arrow-left" circle click"switchList(left)"></el-button><div class"middle-list&q…

【包邮送书】码农职场:IT人求职就业手册

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

HarmonyOS APP应用开发项目- MCA助手(Day04持续更新中~)

简言&#xff1a; gitee地址&#xff1a;https://gitee.com/whltaoin_admin/money-controller-app.git端云一体化开发在线文档&#xff1a;https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/agc-harmonyos-clouddev-view-0000001700053733-V5注&#xff1a;…

Educational Codeforces Round 168 (Rated for Div. 2)(A~D题题解)

A. Strong Password 思路&#xff1a;想要最长的时间&#xff0c;那么肯定就是如果存在前后相同的字母的时候&#xff0c;在中间插入一个不同的字符 &#xff0c;如果不存在前后相同的字符&#xff0c;直接在最后插入一个和原字符串最后一个字符不同的字符 #include <bits/…

等保学习干货|等保测评2.0技术中间件自查阶段,零基础入门到精通,收藏这一篇就够了

0x01 前言 以下是根据我国网络安全体系制订的一系列保护流程进行的等级保护测评。该测评针对已有和将上线的业务服务的基础设施&#xff08;系统、数据库、中间件等&#xff09;&#xff0c;执行一系列检查以确保安全合规。本次先行分享学习等保中的技术自查阶段知识&#xff…

ubuntu24.04 LTS安装BackupPC备份软件

一、安装BackupPC 默认情况下&#xff0c;BackupPC 在 ubuntu24.04 LTS 默认存储库中可用。您只需运行以下命令即可安装它&#xff1a; apt-get install backuppc -y在安装过程中&#xff0c;您将被要求选择邮件配置的类型&#xff0c;如下所示&#xff1a; 选择仅限本地&…

在 VueJS 中使用 Keep-Alive 处理窗口调整事件(在使用keep-alive缓存组件时,处理多个vue页面的resize事件)

前言 我们在使用 VueJS 开发复杂的单页应用程序时&#xff0c;我们经常需要管理组件的生命周期事件&#xff0c;以确保它们在特定的条件下正常工作。例如&#xff0c;当窗口大小调整时&#xff0c;我们可能需要重新绘制某些组件。这里我们详细介绍一下&#xff0c;如何在使用 …

安装docker-东方通tongRDS

首先&#xff0c;确保你的系统已经安装了Docker。你可以在终端中运行以下命令来检查Docker是否已经安装&#xff1a; docker --version接下来&#xff0c;你需要从Docker hub上拉取东方通tongRDS的镜像。在终端中运行以下命令&#xff1a; docker pull dongfangtongrds/tongr…

Unity Camera

课程目标 1. 了解摄像机&#xff08;camera&#xff09;不同视角的设计与实现&#xff1b;2. 感受在不同摄像机视角下观察虚拟场景。 喜欢玩游戏或者看3D动漫的朋友可以回忆在虚拟场景中摄像头的运动变化带来的视觉感受&#xff0c;例如&#xff1a;摄像头给场景中的主角来个…