vue react中的excel導(dǎo)入和導(dǎo)出功能
excel導(dǎo)入和導(dǎo)出是后臺管理系統(tǒng)常見的功能。
當我們把信息化系統(tǒng)給用戶使用時,用戶經(jīng)常需要把以前在excel里錄入的數(shù)據(jù)導(dǎo)入的信息化系統(tǒng)里,這樣為用戶提供了很大的方便。
在用戶使用信息化系統(tǒng)時,也需要把網(wǎng)頁表格里的數(shù)據(jù)導(dǎo)出到excel里,方便進行打印,排版等等。
一、安裝依賴的模塊:
1、file-saver
用于文件操作
2、xlsx用于excel文件處
npm i xlsx@0.17.0 -S npm i file-saver@2.0.5 -S
二、導(dǎo)出功能實現(xiàn)
在自己的項目中新建一個js文件模塊。放入如下代碼:
1、使用dom元素導(dǎo)出
// 1、根據(jù)dom元素導(dǎo)出成excel文件: // 自動分析dom元素導(dǎo)出excel // 參數(shù): // table:表格的dom元素對象 // filename:導(dǎo)出的文件名(不用寫擴展名) export function excelExport(table, filename) { // workbook, const wb = XLSX.utils.table_to_book(table); console.log("wb", wb); /* Export to file (start a download) */ const defaultCellStyle = { font: { name: 'Verdana', sz: 13, color: 'FF00FF88' }, fill: { fgColor: { rgb: 'FFFFAA00' } }, } const wopts = { bookType: 'xlsx', bookSST: false, type: 'binary', cellStyle: true, defaultCellStyle: defaultCellStyle, showGridLines: false, } const wbout = XLSX.write(wb, wopts) const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' }) saveAs(blob, filename + '.xlsx') } function s2ab(s) { console.log("s", s); var buf = new ArrayBuffer(s.length); var view = new Uint8Array(buf); for (var i = 0; i != s.length; ++i) { view[i] = s.charCodeAt(i) & 0xFF; } return buf; }
調(diào)用示例:
excelExport(document.getElementById("t2"), "student");// t2是一個table標簽的id。其實是包含表格標簽的id,會自動分析的。
2、使用json數(shù)組數(shù)據(jù)導(dǎo)出
// 2、根據(jù)json數(shù)據(jù)(數(shù)組)導(dǎo)出成excel文件: // 參數(shù): // data:json數(shù)組 // headers:excel的表頭 // filename:導(dǎo)出的文件名(不用寫擴展名) export function excelExportUseJson(data, headers, filename) { // 使用深克隆不影響原table數(shù)據(jù)的展示 const json = cloneDeep(data) json.forEach(item => { for (let key in item) { if (headers.hasOwnProperty(key)) { item[headers[key]] = item[key] } delete item[key] } }) // excel 對象 const wb = XLSX.utils.book_new() // 創(chuàng)建sheet const ws = XLSX.utils.json_to_sheet(json, { header: Object.values(headers) }) // excel 添加sheet名稱 wb.SheetNames.push(filename) // excel 添加sheet wb.Sheets[filename] = ws const defaultCellStyle = { font: { name: 'Verdana', sz: 13, color: 'FF00FF88' }, fill: { fgColor: { rgb: 'FFFFAA00' } }, } const wopts = { bookType: 'xlsx', bookSST: false, type: 'binary', cellStyle: true, defaultCellStyle: defaultCellStyle, showGridLines: false, } const wbout = XLSX.write(wb, wopts) const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' }) saveAs(blob, filename + '.xlsx') } function cloneDeep(obj) { if (typeof obj !== 'object' || obj === null) { return obj; } let clonedObj = Array.isArray(obj) ? [] : {}; for (let key in obj) { if (obj.hasOwnProperty(key)) { clonedObj[key] = cloneDeep(obj[key]); } } return clonedObj; }
調(diào)用示例:
調(diào)用示例: const books = [ ? { ? id:"878911", ? name:"三國演義" ? }, ? { ? id:"878912", ? name:"西游記" ? } ] excelExportUseJson(books,{id:"編號",name:"書名"},"student02");
三、導(dǎo)入功能實現(xiàn)
// 1、導(dǎo)入成dom元素: // 參數(shù): // data:文件對象(用<input type=file /> 選擇到file對象 // domId:導(dǎo)入的excel顯示的容器 export function httpRequestToHTML(data, domId) { const file = data const types = file.name.split('.')[1] const fileType = ['xlsx', 'xlc', 'xlm', 'xls', 'xlt'].some( (item) => item === types ) if (!fileType) { this.$message.error('格式錯誤!請重新選擇') return } const reader = new FileReader() reader.readAsArrayBuffer(file, 'utf-8'); return new Promise(function (resolve, reject) { reader.onloadend = function (e) { const data = e.target.result console.log('data', data) const wb = XLSX.read(data, { type: 'buffer' }) const ws = wb.Sheets[wb.SheetNames[0]] console.log('ws', ws) const htmlStr = XLSX.utils.sheet_to_html(ws) resolve(htmlStr); } }); } // 2、導(dǎo)入成json數(shù)據(jù)。 // 參數(shù): // data:文件對象(用<input type=file /> 選擇到file對象 export function httpRequestToJSON(data) { const file = data const types = file.name.split('.')[1] const fileType = ['xlsx', 'xlc', 'xlm', 'xls', 'xlt'].some( (item) => item === types ) if (!fileType) { this.$message.error('格式錯誤!請重新選擇') return } const reader = new FileReader() reader.readAsArrayBuffer(file, 'utf-8'); return new Promise(function (resolve, reject) { reader.onloadend = function (e) { const data = e.target.result console.log('data', data) const wb = XLSX.read(data, { type: 'buffer' }) const ws = wb.Sheets[wb.SheetNames[0]] let arr = XLSX.utils.sheet_to_json(ws); resolve(arr); } }); } // 封裝:把excel轉(zhuǎn)成html或者json。 // 參數(shù): // file:(excel)文件對象 // outtype:是導(dǎo)出的類型(取值:html,json) // 調(diào)用示例: // excelTo(文件對象,"html") // excelTo(文件對象,"json") export function excelImport(file,outtype="json") { const types = file.name.split('.')[1] const fileType = ['xlsx', 'xlc', 'xlm', 'xls', 'xlt'].some( (item) => item === types ) if (!fileType) { this.$message.error('格式錯誤!請重新選擇') return } const reader = new FileReader() reader.readAsArrayBuffer(file, 'utf-8'); return new Promise(function (resolve, reject) { reader.onloadend = function (e) { const data = e.target.result console.log('data', data) const wb = XLSX.read(data, { type: 'buffer' }) const ws = wb.Sheets[wb.SheetNames[0]]; let result = ""; switch(outtype.toLocaleLowerCase()){ case "html":result = XLSX.utils.sheet_to_html(ws);break; case "json":result = XLSX.utils.sheet_to_json(ws);break; default:this.$message.error('輸出類型錯誤,只能取值為 html或者json') } resolve(result); } }); }
調(diào)用示例:
const importFn=(e)=>{ if(e.target.files && e.target.files.length>0){ httpRequestToHTML(e.target.files[0],"TableContainer") } } <input type="file" onChange={importFn} /> <div id="TableContainer"> </div>
四、如果想看完整代碼的,在下面:
1、導(dǎo)入導(dǎo)出的工具庫:excelUtils.js
// 此工具庫是:excel的導(dǎo)入和導(dǎo)出 import * as XLSX from 'xlsx'; // import * as fs from 'file-saver'; import { saveAs } from "file-saver" // 一、excel的導(dǎo)出: // 1、根據(jù)dom元素導(dǎo)出成excel文件: // 自動分析dom元素導(dǎo)出excel // 參數(shù): // table:表格的dom元素對象 // filename:導(dǎo)出的文件名(不用寫擴展名) export function excelExport(table, filename) { // workbook, const wb = XLSX.utils.table_to_book(table); console.log("wb", wb); /* Export to file (start a download) */ const defaultCellStyle = { font: { name: 'Verdana', sz: 13, color: 'FF00FF88' }, fill: { fgColor: { rgb: 'FFFFAA00' } }, } const wopts = { bookType: 'xlsx', bookSST: false, type: 'binary', cellStyle: true, defaultCellStyle: defaultCellStyle, showGridLines: false, } const wbout = XLSX.write(wb, wopts) const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' }) saveAs(blob, filename + '.xlsx') } function s2ab(s) { console.log("s", s); var buf = new ArrayBuffer(s.length); var view = new Uint8Array(buf); for (var i = 0; i != s.length; ++i) { view[i] = s.charCodeAt(i) & 0xFF; } return buf; } // 2、根據(jù)json數(shù)據(jù)(數(shù)組)導(dǎo)出成excel文件: // 參數(shù): // data:json數(shù)組 // headers:excel的表頭 // filename:導(dǎo)出的文件名(不用寫擴展名) export function excelExportUseJson(data, headers, filename) { // 使用深克隆不影響原table數(shù)據(jù)的展示 const json = cloneDeep(data) json.forEach(item => { for (let key in item) { if (headers.hasOwnProperty(key)) { item[headers[key]] = item[key] } delete item[key] } }) // excel 對象 const wb = XLSX.utils.book_new() // 創(chuàng)建sheet const ws = XLSX.utils.json_to_sheet(json, { header: Object.values(headers) }) // excel 添加sheet名稱 wb.SheetNames.push(filename) // excel 添加sheet wb.Sheets[filename] = ws const defaultCellStyle = { font: { name: 'Verdana', sz: 13, color: 'FF00FF88' }, fill: { fgColor: { rgb: 'FFFFAA00' } }, } const wopts = { bookType: 'xlsx', bookSST: false, type: 'binary', cellStyle: true, defaultCellStyle: defaultCellStyle, showGridLines: false, } const wbout = XLSX.write(wb, wopts) const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' }) saveAs(blob, filename + '.xlsx') } function cloneDeep(obj) { if (typeof obj !== 'object' || obj === null) { return obj; } let clonedObj = Array.isArray(obj) ? [] : {}; for (let key in obj) { if (obj.hasOwnProperty(key)) { clonedObj[key] = cloneDeep(obj[key]); } } return clonedObj; } // 二、從excel文件導(dǎo)入到項目里。 // 1、導(dǎo)入成dom元素: // 參數(shù): // data:文件對象(用<input type=file /> 選擇到file對象 // domId:導(dǎo)入的excel顯示的容器 export function httpRequestToHTML(data, domId) { const file = data const types = file.name.split('.')[1] const fileType = ['xlsx', 'xlc', 'xlm', 'xls', 'xlt'].some( (item) => item === types ) if (!fileType) { this.$message.error('格式錯誤!請重新選擇') return } const reader = new FileReader() reader.readAsArrayBuffer(file, 'utf-8'); return new Promise(function (resolve, reject) { reader.onloadend = function (e) { const data = e.target.result console.log('data', data) const wb = XLSX.read(data, { type: 'buffer' }) const ws = wb.Sheets[wb.SheetNames[0]] console.log('ws', ws) const htmlStr = XLSX.utils.sheet_to_html(ws) resolve(htmlStr); } }); } // 2、導(dǎo)入成json數(shù)據(jù)。 // 參數(shù): // data:文件對象(用<input type=file /> 選擇到file對象 export function httpRequestToJSON(data) { const file = data const types = file.name.split('.')[1] const fileType = ['xlsx', 'xlc', 'xlm', 'xls', 'xlt'].some( (item) => item === types ) if (!fileType) { this.$message.error('格式錯誤!請重新選擇') return } const reader = new FileReader() reader.readAsArrayBuffer(file, 'utf-8'); return new Promise(function (resolve, reject) { reader.onloadend = function (e) { const data = e.target.result console.log('data', data) const wb = XLSX.read(data, { type: 'buffer' }) const ws = wb.Sheets[wb.SheetNames[0]] let arr = XLSX.utils.sheet_to_json(ws); resolve(arr); } }); } // 封裝:把excel轉(zhuǎn)成html或者json。 // 參數(shù): // file:(excel)文件對象 // outtype:是導(dǎo)出的類型(取值:html,json) // 調(diào)用示例: // excelTo(文件對象,"html") // excelTo(文件對象,"json") export function excelImport(file,outtype="json") { const types = file.name.split('.')[1] const fileType = ['xlsx', 'xlc', 'xlm', 'xls', 'xlt'].some( (item) => item === types ) if (!fileType) { this.$message.error('格式錯誤!請重新選擇') return } const reader = new FileReader() reader.readAsArrayBuffer(file, 'utf-8'); return new Promise(function (resolve, reject) { reader.onloadend = function (e) { const data = e.target.result console.log('data', data) const wb = XLSX.read(data, { type: 'buffer' }) const ws = wb.Sheets[wb.SheetNames[0]]; let result = ""; switch(outtype.toLocaleLowerCase()){ case "html":result = XLSX.utils.sheet_to_html(ws);break; case "json":result = XLSX.utils.sheet_to_json(ws);break; default:this.$message.error('輸出類型錯誤,只能取值為 html或者json') } resolve(result); } }); }
2、組件代碼:
<template> <el-button @click="drawer = true" v-if="crud.charAt(0) === '1'">添加輪播圖</el-button> <el-button @click="toExcel01">excel導(dǎo)出(用dom元素)</el-button> <el-button @click="toExcel02">excel導(dǎo)出(用json數(shù)組)</el-button> <!-- <el-button @click="fromExcel">excel導(dǎo)入</el-button> --> <!-- <input type="file" @change="fromExcel" /> --> <el-upload ref="upload" class="upload-demo" :limit="1" :on-change="changeFn" :on-exceed="handleExceed" :auto-upload="false" :show-file-list="false"> <template #trigger> <el-button type="primary">excel導(dǎo)入</el-button> </template> </el-upload> <el-button @click="batchSave">批量提交</el-button> <el-button @click="clearAll">清空輪播圖數(shù)據(jù)</el-button> <el-divider /> <el-table ref="table" id="table01" :data="bannerList" height="600px" style="width: 100%"> <el-table-column prop="bannerid" label="編號" width="180" /> <el-table-column label="圖片" width="180"> <template #default="scope"> <img class="img" :src="scope.row.img" /> </template> </el-table-column> <el-table-column label="是否啟用" v-if="crud.charAt(2) === '1'"> <template #default="scope"> <el-switch v-model="scope.row.flag" /> </template> </el-table-column> <el-table-column label="跳轉(zhuǎn)連接"> <template #default="scope"> <el-link :href="scope.row.link" type="primary" target="_blank">跳轉(zhuǎn)連接</el-link> </template> </el-table-column> <el-table-column prop="alt" label="圖片提示" /> <el-table-column label="操作" v-if="crud.charAt(2) === '1' || crud.charAt(3) === '1'"> <template #default="scope"> <el-button type="danger" v-if="crud.charAt(3) === '1'" >刪除</el-button> <el-button type="danger" v-if="crud.charAt(2) === '1'">修改</el-button> </template> </el-table-column> </el-table> <el-drawer v-model="drawer" title="添加輪播圖" direction="rtl" :before-close="handleClose"> <AddBannerVue ref="addBannerRef" @ok="okHandle" @cancel="closeDrawer"></AddBannerVue> </el-drawer> <hr /> <div id="container"></div> </template> <script lang="ts" setup> import { useRoute } from "vue-router"; import { getBannerApi, addBannerApi,clearBannerApi } from "@/api/banner"; import { onMounted, reactive, ref } from "vue"; import { ElMessageBox } from 'element-plus' import type { UploadInstance, UploadProps, UploadRawFile,UploadFile } from 'element-plus' import AddBannerVue from "./AddBanner.vue"; import type { IBanner } from "@/myTypes" import { excelExport, excelExportUseJson, excelImport } from "@/utils/excelUtils"; const $route = useRoute();//this.$route const crud: string = $route.meta.crud as string; const bannerList = reactive<Array<IBanner>>([]); // 清空輪播圖 const clearAll=()=>{ clearBannerApi().then(res=>{ if(res.data.code==="200"){ ElMessageBox.alert("清空成功", "提示", { confirmButtonText: "確定", callback: () => { getBannerList(); } }); } }).catch(err=>{ console.log("清空失敗",err); }) } // 獲取輪播圖的數(shù)據(jù) function getBannerList() { getBannerApi().then(res => { if (res.data.code === "200") { bannerList.length = 0; bannerList.push(...res.data.data); } }).catch(err => { console.log("獲取輪播圖失敗,err", err); }) } // 在初次渲染完畢后,獲取輪播圖數(shù)據(jù) // onMounted(()=>getBannerList()); getBannerList(); // 添加相關(guān): // const drawer = ref(false); function okHandle() { closeDrawer(); getBannerList(); } // 關(guān)閉抽屜 const closeDrawer = () => { drawer.value = false; } const addBannerRef = ref(); const handleClose = (done: () => void) => { ElMessageBox.confirm('親,您真的要關(guān)閉嗎?') .then(() => { console.log("點了確定"); addBannerRef.value.clearData(); done(); }) .catch(() => { // catch error console.log("點了取消"); }) } onMounted(() => console.log("父組件:mounted")) const toExcel01 = () => { excelExport(document.getElementById("table01"), "banners"); } const toExcel02 = () => { // const arr = bannerList.map(item => ({ // bannerid: item.bannerid, // img: item.img, // flag: item.flag ? "是" : "否" // })) // excelExportUseJson(arr, { // bannerid: "編號", // img: "圖片", // flag: "是否啟用" // }, "bannerList"); excelExportUseJson(bannerList, { bannerid: "編號", img: "圖片", flag: "是否啟用", link: "跳轉(zhuǎn)連接", alt: "圖片提示" }, "bannerList"); } // 從excel文件中導(dǎo)入 const fromExcel = (e: any) => { if (e.target.files && e.target.files.length > 0) { excelImport(e.target.files[0],) .then((arr: any) => { bannerList.length = 0; arr.forEach((item: any) => { bannerList.push({ bannerid: item["編號"], img: item["圖片"], flag: item["是否啟用"], link: item["跳轉(zhuǎn)連接"], alt: item["圖片提示"] }); }) }) } } function batchSave() { let count = 0; bannerList.forEach((item: any) => { addBannerApi(item).then(() => { console.log(`添加成功了${++count}條`); }) }) } const upload = ref<UploadInstance>(); const handleExceed: UploadProps['onExceed'] = (files) => { upload.value!.clearFiles() const file = files[0] as UploadRawFile upload.value!.handleStart(file); } const changeFn=(file:UploadFile)=>{ console.log("excelImport:file",file); excelImport(file.raw as File) .then((arr: any) => { bannerList.length = 0; arr.forEach((item: any) => { bannerList.push({ bannerid: item["編號"], img: item["圖片"], flag: item["是否啟用"], link: item["跳轉(zhuǎn)連接"], alt: item["圖片提示"] }); }) }) } </script> <style lang="scss" scoped> .img { width: 100%; height: 100px; } </style>
到此這篇關(guān)于vue中或者react中的excel導(dǎo)入和導(dǎo)出的文章就介紹到這了,更多相關(guān)vue excel導(dǎo)入導(dǎo)出內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解從Vue.js源碼看異步更新DOM策略及nextTick
本篇文章主要介紹了從Vue.js源碼看異步更新DOM策略及nextTick,具有一定的參考價值,感興趣的小伙伴們可以參考一2017-10-10Vue+Typescript中在Vue上掛載axios使用時報錯問題
這篇文章主要介紹了Vue+Typescript中在Vue上掛載axios使用時報錯問題,本文給大家介紹的非常詳細,具有一定的參考借鑒價值 ,需要的朋友可以參考下2019-08-08Vue網(wǎng)頁html轉(zhuǎn)換PDF(最低兼容ie10)的思路詳解
這篇文章主要介紹了Vue網(wǎng)頁html轉(zhuǎn)換PDF(最低兼容ie10)的思路詳解,實現(xiàn)此功能需要引入兩個插件,需要的朋友可以參考下2017-08-08