Vue3+TypeScript+ Element Plus 從Excel文件導入數據,無后端(點擊按鈕,選擇Excel文件,由前端解析數據)

在 Vue 3 + TypeScript + Element Plus 中實現文件導入功能,可以通過以下步驟完成:

1. 安裝依賴

bash

復制

下載

npm install xlsx  # 用于解析Excel文件
npm install @types/xlsx -D  # TypeScript類型聲明

2. 組件實現

vue

復制

下載

<template><div><!-- 隱藏的原生文件輸入 --><input type="file"ref="fileInput"@change="handleFileChange"accept=".xlsx, .xls, .csv"style="display: none"><!-- Element Plus 按鈕觸發文件選擇 --><el-button type="primary"@click="triggerFileInput"><el-icon><upload /></el-icon>導入文件</el-button><!-- 顯示導入數據 --><el-table :data="tableData" v-if="tableData.length"><el-table-column v-for="(header, index) in tableHeaders" :key="index":prop="header":label="header"/></el-table></div>
</template><script setup lang="ts">
import { ref } from 'vue';
import * as XLSX from 'xlsx';
import type { UploadInstance } from 'element-plus';
import { ElMessage } from 'element-plus';// 類型定義
interface TableData {[key: string]: any;
}// 響應式數據
const fileInput = ref<HTMLInputElement | null>(null);
const tableData = ref<TableData[]>([]);
const tableHeaders = ref<string[]>([]);// 觸發文件選擇
const triggerFileInput = () => {if (fileInput.value) {fileInput.value.value = ''; // 重置以允許重復選擇相同文件fileInput.value.click();}
};// 處理文件選擇
const handleFileChange = (e: Event) => {const input = e.target as HTMLInputElement;if (!input.files?.length) return;const file = input.files[0];const reader = new FileReader();reader.onload = (e) => {try {const data = e.target?.result as ArrayBuffer;processExcel(data);} catch (error) {console.error('文件解析失敗:', error);ElMessage.error('文件解析失敗');}};reader.readAsArrayBuffer(file);
};// 處理Excel數據
const processExcel = (data: ArrayBuffer) => {const workbook = XLSX.read(data, { type: 'array' });const firstSheetName = workbook.SheetNames[0];const worksheet = workbook.Sheets[firstSheetName];// 轉換為JSONconst jsonData: TableData[] = XLSX.utils.sheet_to_json(worksheet);if (jsonData.length > 0) {// 獲取表頭tableHeaders.value = Object.keys(jsonData[0]);tableData.value = jsonData;ElMessage.success(`成功導入 ${jsonData.length} 條數據`);} else {ElMessage.warning('未找到有效數據');}
};
</script>

3. 功能說明

  1. 文件選擇觸發

    • 隱藏原生?<input type="file">?元素

    • 通過Element Plus按鈕觸發文件選擇

  2. 文件處理流程

    • 使用?FileReader?讀取文件內容

    • 通過?xlsx?庫解析Excel數據

    • 將工作表轉換為JSON格式

    • 提取表頭和數據

  3. 數據展示

    • 使用Element Plus的?<el-table>?動態渲染數據

    • 自動識別表頭生成列

4. 擴展功能建議

  1. 文件類型驗證

ts

復制

下載

// 在handleFileChange中添加
const validTypes = ['application/vnd.ms-excel','application/vnd.openxmlformats-officedocument.spreadsheetml.sheet','text/csv'
];if (!validTypes.includes(file.type)) {ElMessage.error('請上傳Excel或CSV文件');return;
}
  1. 數據清洗

ts

復制

下載

// 在processExcel后添加數據清洗邏輯
const cleanData = jsonData.map(item => {// 示例:移除空值return Object.fromEntries(Object.entries(item).filter(([_, value]) => value !== null));
});
  1. 上傳到服務器

ts

復制

下載

import axios from 'axios';const uploadData = async () => {try {const response = await axios.post('/api/import', {data: tableData.value,headers: tableHeaders.value});ElMessage.success(`服務器導入成功: ${response.data.message}`);} catch (error) {ElMessage.error('服務器導入失敗');}
};

5. 注意事項

  1. 大文件處理

    • 添加文件大小限制

    • 使用Web Worker防止界面卡頓

    • 分片讀取處理

  2. 安全性

    • 驗證文件內容格式

    • 防止XSS攻擊(特別是CSV文件)

    • 服務器端二次驗證

  3. 用戶體驗

    • 添加加載狀態

    • 顯示解析進度

    • 錯誤文件類型提示

vue

復制

下載

<!-- 加載狀態示例 -->
<el-button :loading="isLoading" @click="triggerFileInput"
>導入文件
</el-button>

這個實現方案提供了完整的文件導入流程,包括前端解析和展示,可根據實際需求擴展服務器上傳功能。

6.實例代碼

點擊按鈕,選擇Excel文件,由前端解析數據,實現從Excel文件導入數據

1、導入的黃金搭檔【按鈕 + 輸入框】,按鈕顯示充門面,輸入框隱藏干實事

2、導入核心功能封裝成工具

在組件中使用

ReagentInDialog.vue

<script setup lang="ts" name="ReagentInDialog">import { importExcelFileByClient } from "@/utils/excelUtils";// 文件輸入實例對象
const fileInputRef = ref<HTMLInputElement | null>(null);// 導入
const onImportClick = () => {// 模擬點擊元素if (fileInputRef.value) {// 重置以允許重復選擇相同文件fileInputRef.value.value = "";fileInputRef.value.click();}
};// 點擊【導入】觸發
const handleImportByClient = async (e: Event) => {// 獲取文件對象const input = e.target as HTMLInputElement;if (!input.files?.length) return;const file = input.files[0];// 鍵值列名映射表const keyColMap: Record<string, string> = {編號: "materialNo",試劑編號: "reagentNo",試劑名稱: "reagentName",規格型號: "reagentSpec",單位: "reagentUnit",批號: "batchNo",有效期至: "validityDate",入庫數量: "amount",入庫金額: "total"};// 導入文件,由前端解析文件,獲取數據const dataList = <IReagentInByCkDetail[]>await importExcelFileByClient(file, keyColMap);// 加載數據dataList.forEach((item) => {tableData.value.push({id: -(tableData.value.length + 1),materialNo: (tableData.value.length + 1).toString(),reagentNo: item.reagentNo,reagentName: item.reagentName});});// 等待 DOM 渲染完畢await nextTick();// 全選tableRef.value?.toggleAllSelection();
};</script><template><el-button class="in-btn" type="primary" plain @click="onImportClick">導入</el-button><!-- 文件輸入元素,不顯示,通過點擊按鈕【導入】執行 onImportClick,模擬點擊該元素,從而觸發 handleImportByClient 事件 --><inputref="fileInputRef"type="file"accept=".xls, .xlsx"style="display: none"@change="handleImportByClient" /></template>

導入工具

excelUtils.ts

import { convertFileSize } from "@/utils/pubUtils";
import { ElMessage } from "element-plus";
import * as xlsx from "xlsx";/*** 從Excel文件導入數據,由前端解析文件,獲取數據* @param file 導入文件* @param colKeyMap 列名鍵值映射,key --> value,如:excel中列名為【樣品編號】,其鍵值設置對應為【sampleNo】* @returns 列表數據*/
export async function importExcelFileByClient(file: any, keyColMap: Record<string, string>) {// 定義及初始化需要返回的列表數據let dataList: any[] = [];// 文件校驗// 校驗文件名后綴if (!/\.(xls|xlsx)$/.test(file.name)) {ElMessage.warning("請導入excel文件!");return dataList;}// 校驗文件格式// application/vnd.ms-excel 為 .xls文件// application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 為 .xlsx文件else if (file.type !== "application/vnd.ms-excel" &&file.type !== "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") {ElMessage.warning("excel文件已損壞,請檢查!");return dataList;}// 校驗文件大小else if (convertFileSize(file.size, "B", "MB") > 1) {ElMessage.warning("文件大小不能超過1MB!");return dataList;}// 文件讀取let fileReader = new FileReader();// 以二進制的方式讀取文件內容fileReader.readAsArrayBuffer(file);// 等待打開加載完成文件,其實就是執行 fileReader.onloadend = () => {},返回 true 表示成功,false 表示失敗let result = await loadedFile(fileReader);if (result) {// 獲取文件數據let fileData = fileReader.result;// 讀取工作薄 workbooklet workbook = xlsx.read(fileData, { type: "array" });// 表格是有序列表,因此可以取多個 Sheet,這里取第一個 Sheetlet sheet = workbook.SheetNames[0];// 將表格內容生成 json 數據let sheetJson = xlsx.utils.sheet_to_json(workbook.Sheets[sheet]);// 限制最多只能導入1000條數據,預防惡意操作導入超大量數據if (sheetJson.length > 1000) {ElMessage.warning("一次最多只能導入1000條數據!");return dataList;}// 格式化表格json數據 sheetJson,轉換成在excel表中看到的那種直觀數據dataList = formatSheetJson(sheetJson, keyColMap);}// 返回列表數據return dataList;
}/*** 加載文件* 是否打開加載了文件,因為 fileReader.onloadend 是異步任務,程序執行時,不會執行完 onloadend 內部的代碼再往下執行,* 而是執行到 onloadend 內部時,又跳出 onloadend,執行 onloadend 外部的代碼* 故將 fileReader.onloadend 用 Promise<boolean> 返回對象包裹,程序執行時用await loadedFile,這樣就會執行完 onloadend 內部的代碼再往下執行* 【要讓 異步任務 不異步執行,可以用一個方法將其包裹,并且該方法返回Promise對象,執行該方法時用 await】* @param fileReader 文件讀取器* @returns 響應結果*/
function loadedFile(fileReader: FileReader): Promise<boolean> {return new Promise((resolve, reject) => {// 讀取文件,文件讀取完成觸發該事件fileReader.onloadend = () => {try {// 成功打開加載完文件數據resolve(true);} catch (error) {// 失敗reject(false);}};});
}/*** 將表格json數據 sheetJson 轉換成列表數據* @param sheetJson 表格json數據* @param colKeyMap 列名鍵值映射,key --> value,如:excel中列名為【樣品編號】,其鍵值設置對應為【sampleNo】* @returns 列表數據*/
function formatSheetJson(sheetJson: any[], keyColMap: Record<string, string>): any[] {// 無內容,返回空數據if (!sheetJson.length) return [];let result = sheetJson;// 判斷是否有表頭,有表頭的話,sheetJson對象必然有__EMPTY屬性let hasTableHead = !!sheetJson[0]["__EMPTY"];// 擁有表頭的數據,重新轉換列標題if (hasTableHead) {// 獲取對象中所有屬性的名稱let header = sheetJson.shift();// 數據let data: any[] = [];// 遍歷對象所有屬性(列信息)Object.keys(header).forEach((key) => {// 遍歷數據(行信息)sheetJson.forEach((item, index) => {// 構建對象內容let obj = data[index] || {};// 對象增加屬性,并給屬性賦值數據(行列信息)obj[header[key]] = item[key];// 最終給數據行數據賦值對象內容data[index] = obj;});});result = data;}// 將表格對應的文字轉換為 keylet dataList: any[] = [];result.forEach((item) => {let newItem: any = {};Object.keys(item).forEach((key) => {newItem[keyColMap[key]] = item[key];});dataList.push(newItem);});// 返回列表數據return dataList;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/84464.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/84464.shtml
英文地址,請注明出處:http://en.pswp.cn/web/84464.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

一些torch函數用法總結

1.torch.nonzero(input, *, as_tupleFalse) 作用&#xff1a;在PyTorch中用于返回輸入張量中非零元素的位置索引。 返回值&#xff1a;返回一個張量&#xff0c;每行代表一個非零元素的索引。 參數含義&#xff1a; &#xff08;1&#xff09;input:輸入的PyTorch 張量。 …

moments_object_model_3d這么理解

這篇文章是我對這個算子的理解,和三個輸出結果分別用在什么地方 算子本身 moments_object_model_3d( : : ObjectModel3D, MomentsToCalculate : Moments) MomentsToCalculate:對應三個可選參數,分別是 1, mean_points: 就是點云在xyz方向上坐標的平均值 2, central_m…

性能測試|數據說話!在SimForge平臺上用OpenRadioss進行汽車碰撞仿真,究竟多省時?

Radioss是碰撞仿真領域中十分成熟的有限元仿真軟件&#xff0c;可以對工程中許多非線性問題進行求解&#xff0c;例如汽車碰撞、產品跌落、導彈爆炸、流固耦合分析等等。不僅可以提升產品的剛度、強度、碰撞的安全性能等&#xff0c;還可以在降低產品研發成本的同時提升研發效率…

數據結構學習——KMP算法

//KMP算法 #include <iostream> #include <string> #include <vector> #include <cstdlib>using namespace std;//next數組值的推導void getNext(string &str, vector<int>& next){int strlong str.size();//next數組的0位為0next[0]0;…

博士,超28歲,出局!

近日&#xff0c;長沙市望城區《2025年事業引才博士公開引進公告》引發軒然大波——博士崗位年齡要求28周歲及以下&#xff0c;特別優秀者也僅放寬至30周歲。 圖源&#xff1a;網絡 這份規定讓眾多"高齡"博士生直呼不合理&#xff0c;并在社交平臺掀起激烈討論。 圖源…

使用Nuitka打包Python程序,編譯為C提高執行效率

在 Python 的世界里&#xff0c;代碼打包與發布一直是開發者關注的重要話題。前面我們介紹了Pyinstaller的使用&#xff0c;盡管 PyInstaller 是最常用的工具之一&#xff0c;但對于性能、安全性、兼容性有更高要求的項目&#xff0c;Nuitka 正迅速成為更優的選擇。本文將全面介…

基于機器學習的惡意請求檢測

好久沒寫文章了&#xff0c;忙畢業設計ING&#xff0c;終于做好了發出來。 做了針對惡意URL的檢測&#xff0c;改進了楊老師這篇參考文獻的惡意請求檢測的方法 [網絡安全自學篇] 二十三.基于機器學習的惡意請求識別及安全領域中的機器學習-CSDN博客 選擇使用了XGBoost算法進…

深入理解XGBoost(何龍 著)學習筆記(五)

深入理解XGBoost&#xff08;何龍 著&#xff09;學習筆記&#xff08;五&#xff09; 本文接上一篇&#xff0c;內容為線性回歸&#xff0c;介紹三部分&#xff0c;首先介紹了"模型評估”&#xff0c;然后分別提供了線性回歸的模型代碼&#xff1a;scikit-learn的Linear…

工業級MySQL基準測試專家指南

工業級MySQL基準測試專家指南 一、深度風險識別增強版 風險類型典型表現進階檢測方案K8s存儲性能抖動PVC卷IOPS驟降50%使用kubestone進行CSI驅動壓力測試HTAP讀寫沖突OLAP查詢導致OLTP事務超時用TPCH+Sysbench混合負載測試冷熱數據分層失效壓縮表查詢耗時激增10倍監控INNODB_C…

Spring WebFlux和Spring MVC的對比

原文網址&#xff1a;Spring WebFlux和Spring MVC的對比-CSDN博客 簡介 本文介紹Spring WebFlux和Spring MVC的區別。 Webflux&#xff1a;是異步非阻塞的&#xff08;IO多路復用&#xff09;&#xff0c;基于Netty。適合網絡轉發類的應用&#xff0c;比如&#xff1a;網關。…

解析401 Token過期自動刷新機制:Kotlin全棧實現指南

在現代Web應用中&#xff0c;Token過期導致的401錯誤是影響用戶體驗的關鍵問題。本文將手把手實現一套完整的Token自動刷新機制&#xff0c;覆蓋從原理到實戰的全過程。 一、為什么需要Token自動刷新&#xff1f; 當用戶使用應用時&#xff0c;會遇到兩種典型場景&#xff1a;…

《解構線性數據結構的核心骨架:從存儲模型到操作范式的深度解析》

線性數據結構概述 線性數據結構是數據元素按線性順序排列的集合,每個元素有唯一的前驅和后繼(除首尾元素)。常見類型包括數組、隊列、鏈表和棧,每種結構在存儲和操作上具有獨特特性。 線性表:顧名思義,線性表就是數據排成像一條線的結構。每個線性表上的數據最多只有前和后…

HW藍隊工作流程

HW藍隊工作流程 由多領域安全專家組成攻擊隊&#xff0c;在保障業務系統安全的前提下&#xff0c;直接在真實網絡環境開展對抗&#xff0c;對參演單位目標系進行可控、可審計的網絡安全實戰攻擊&#xff0c;通過攻防演習檢驗參演單位的安全防護和應急處置能力&#xff0c;提高…

語音相關-瀏覽器的自動播放策略研究和websocket研究

策略詳情 媒體參與度 AudioContext音頻API的實現 new Audio音頻API的實現 相關實踐 網頁端 使用new Audio創建的音頻對象進行音頻播放的時候&#xff0c;如果用戶沒有與頁面進行交互&#xff0c;那么會報錯如下&#xff1a; 使用AudioContext創建的對象播放音頻&#xff0c;…

Linux操作系統網絡服務模塊一DHCP服務概述

前言&#xff1a; 在Linux網絡服務體系架構中&#xff0c;?DHCP&#xff08;Dynamic Host Configuration Protocol&#xff09;?? 作為核心服務之一&#xff0c;承擔著局域網內主機網絡參數動態分配的關鍵任務。其設計初衷是解決傳統手動配置IP地址的效率瓶頸與錯誤風…

FPGA基礎 -- Verilog語言要素之變量類型

Verilog 變量類型&#xff08;Variable Types&#xff09; 一、什么是變量類型&#xff1f; 在 Verilog 中&#xff0c;變量類型用于保存過程賦值結果&#xff08;由 always 或 initial 塊賦值&#xff09;&#xff0c;通常用于建模寄存器、狀態、計數器等“帶記憶”的硬件行為…

使用Haporxy搭建Web群集

目錄 一、案例分析 1.案例概述 2.案例前置知識點 2.1 HTTP請求 2.2 負載均衡常用調度算法 2.3常見的Web群集調度器 3.案例環境 3.1本案例環境 二、案例實施 1.搭建兩臺web服務器 2.安裝Haproxy 3.haproxy服務器配置 修改haproxy的配置文件 4.測試web群集 5.haproxy的日…

pikachu靶場通關筆記38 目錄遍歷(路徑遍歷)

目錄 一、目錄遍歷 二、源碼分析 三、目錄遍歷與文件包含 四、實戰滲透 1、進入靶場 2、目錄遍歷 &#xff08;1&#xff09;訪問ace.min.css &#xff08;2&#xff09;訪問fileinclude.php 本系列為《pikachu靶場通關筆記》滲透實戰&#xff0c;本文通過對目錄遍歷源…

現代C++:std::string全方位碾壓C字符串

在 C 中引入的 std::string 是對 C 語言中 char* 和 const char* 的一種現代化封裝和增強。它不僅解決了 C 字符串的許多缺陷&#xff08;如安全性、內存管理、易用性等&#xff09;&#xff0c;還提供了豐富的 API 來簡化字符串操作。本文將從多個維度詳細對比 std::string 與…

20250619周四:Atlassian

今天主要把conference上的A xxx的所有資料大體看了一遍&#xff0c;花了兩個多小時。 公司的這個conference系統&#xff0c;共實就是一個大型的可多人在線編輯的文件系統。差不多所有的資料都共享在上面。這對于多人參與的項目管理&#xff0c;還是相當方便的。 Atlassian最特…