vue react中的excel導入和導出功能
excel導入和導出是后臺管理系統(tǒng)常見的功能。
當我們把信息化系統(tǒng)給用戶使用時,用戶經(jīng)常需要把以前在excel里錄入的數(shù)據(jù)導入的信息化系統(tǒng)里,這樣為用戶提供了很大的方便。
在用戶使用信息化系統(tǒng)時,也需要把網(wǎng)頁表格里的數(shù)據(jù)導出到excel里,方便進行打印,排版等等。
一、安裝依賴的模塊:
1、file-saver 用于文件操作
2、xlsx用于excel文件處
npm i xlsx@0.17.0 -S npm i file-saver@2.0.5 -S
二、導出功能實現(xiàn)
在自己的項目中新建一個js文件模塊。放入如下代碼:
1、使用dom元素導出
// 1、根據(jù)dom元素導出成excel文件:
// 自動分析dom元素導出excel
// 參數(shù):
// table:表格的dom元素對象
// filename:導出的文件名(不用寫擴展名)
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;
}調用示例:
excelExport(document.getElementById("t2"), "student");// t2是一個table標簽的id。其實是包含表格標簽的id,會自動分析的。2、使用json數(shù)組數(shù)據(jù)導出
// 2、根據(jù)json數(shù)據(jù)(數(shù)組)導出成excel文件:
// 參數(shù):
// data:json數(shù)組
// headers:excel的表頭
// filename:導出的文件名(不用寫擴展名)
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;
}調用示例:
調用示例:
const books = [
? {
? id:"878911",
? name:"三國演義"
? },
? {
? id:"878912",
? name:"西游記"
? }
]
excelExportUseJson(books,{id:"編號",name:"書名"},"student02");三、導入功能實現(xiàn)
// 1、導入成dom元素:
// 參數(shù):
// data:文件對象(用<input type=file /> 選擇到file對象
// domId:導入的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、導入成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轉成html或者json。
// 參數(shù):
// file:(excel)文件對象
// outtype:是導出的類型(取值:html,json)
// 調用示例:
// 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);
}
});
}調用示例:
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、導入導出的工具庫:excelUtils.js
// 此工具庫是:excel的導入和導出
import * as XLSX from 'xlsx';
// import * as fs from 'file-saver';
import { saveAs } from "file-saver"
// 一、excel的導出:
// 1、根據(jù)dom元素導出成excel文件:
// 自動分析dom元素導出excel
// 參數(shù):
// table:表格的dom元素對象
// filename:導出的文件名(不用寫擴展名)
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ù)組)導出成excel文件:
// 參數(shù):
// data:json數(shù)組
// headers:excel的表頭
// filename:導出的文件名(不用寫擴展名)
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文件導入到項目里。
// 1、導入成dom元素:
// 參數(shù):
// data:文件對象(用<input type=file /> 選擇到file對象
// domId:導入的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、導入成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轉成html或者json。
// 參數(shù):
// file:(excel)文件對象
// outtype:是導出的類型(取值:html,json)
// 調用示例:
// 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導出(用dom元素)</el-button>
<el-button @click="toExcel02">excel導出(用json數(shù)組)</el-button>
<!-- <el-button @click="fromExcel">excel導入</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導入</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="跳轉連接">
<template #default="scope">
<el-link :href="scope.row.link" type="primary" target="_blank">跳轉連接</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();
// 添加相關:
//
const drawer = ref(false);
function okHandle() {
closeDrawer();
getBannerList();
}
// 關閉抽屜
const closeDrawer = () => {
drawer.value = false;
}
const addBannerRef = ref();
const handleClose = (done: () => void) => {
ElMessageBox.confirm('親,您真的要關閉嗎?')
.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: "跳轉連接",
alt: "圖片提示"
}, "bannerList");
}
// 從excel文件中導入
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["跳轉連接"],
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["跳轉連接"],
alt: item["圖片提示"]
});
})
})
}
</script>
<style lang="scss" scoped>
.img {
width: 100%;
height: 100px;
}
</style>到此這篇關于vue中或者react中的excel導入和導出的文章就介紹到這了,更多相關vue excel導入導出內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
詳解從Vue.js源碼看異步更新DOM策略及nextTick
本篇文章主要介紹了從Vue.js源碼看異步更新DOM策略及nextTick,具有一定的參考價值,感興趣的小伙伴們可以參考一2017-10-10
Vue+Typescript中在Vue上掛載axios使用時報錯問題
這篇文章主要介紹了Vue+Typescript中在Vue上掛載axios使用時報錯問題,本文給大家介紹的非常詳細,具有一定的參考借鑒價值 ,需要的朋友可以參考下2019-08-08
Vue網(wǎng)頁html轉換PDF(最低兼容ie10)的思路詳解
這篇文章主要介紹了Vue網(wǎng)頁html轉換PDF(最低兼容ie10)的思路詳解,實現(xiàn)此功能需要引入兩個插件,需要的朋友可以參考下2017-08-08

