注:末尾有完整代码
效果图
Excel
1、下载依赖
xlsx是导入所需依赖 file-saver是导出所需依赖
npm install xlsx --save
npm install file-saver --save
2、组件中导入
import * as XLSX from "xlsx/xlsx.mjs";
import FileSaver from "file-saver";
3、html部分
el-upload内部分属性:
action:必填字段,这里没有填服务器地址。 :auto-upload=“false”:将文件进行截取,避免上传,配合action属性使用 :on-change=“handle”: 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
el-table:el-table-column序号显示可根据需求删除
<template>
<div id="Excel">
<!-- 上传 -->
<el-upload
action
accept=".xlsx, .xls"
:auto-upload="false"
:show-file-list="false"
:on-change="handle"
>
<el-button type="primary" class="imExcelBtn"
>导入Excel</el-button>
</el-upload>
<!-- 表格名称及导出和关闭预览的按钮 -->
<div class="excelName" v-if="tableKey">
<div class="left"></div>
<div class="center">{{ excelName }}</div>
<div class="right">
<el-button type="success" @click="exportExcel">导出为Excel</el-button>
<el-button type="danger" @click="closeExcel">关闭预览</el-button>
</div>
</div>
<!-- 表格 -->
<el-table
:data="tableData"
style="width: 100%"
max-height="500"
:key="tableKey"
:header-cell-style="{
background: '#d2d28e',
color: '#000000',
}"
v-if="tableKey"
id="excelTable"
border
stripe
>
<!-- 第一个el-table-column 可根据需求删除-->
<el-table-column
header-align="center"
align="center"
type="index"
label="序号"
width="50"
></el-table-column>
<el-table-column
v-for="(item, index) in tableColumn"
:key="index"
:prop="item.prop"
:label="item.label"
width="width"
>
</el-table-column>
</el-table>
</div>
</template>
4、data部分
data() {
return {
tableKey: false, //表格的key及显示与隐藏
excelName: "", //excel表格名称
excelHeader: [], //excel的表头
tableData: [], //表格数据
tableColumn: [], //表格的表头
};
},
5、methods内函数
// 上传文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
async handle(ev) {
//改变表格key值
this.tableKey = true;
let file = ev.raw;
this.excelName = file.name;
//截取表格文件名
this.excelName = this.excelName.substring(0, this.excelName.lastIndexOf("."));
console.log("上传的未解析源文件", file);
if (!file) {
console.log("文件打开失败");
return;
} else {
let data = await this.readFile(file);
let workbook = XLSX.read(data, { type: "binary" }); //解析二进制格式数据
console.log("二进制数据的解析:", workbook);
let worksheet = workbook.Sheets[workbook.SheetNames[0]]; //获取第一个Sheet
// 调用解析表头方法
this.getHeader(worksheet);
let result = XLSX.utils.sheet_to_json(worksheet); //转换为json数据格式
console.log("最终解析的 json 格式数据:", result);
this.tableData = result;
// 调用处理表头函数
this.setTable();
}
},
//文件读取
readFile(file) {
return new Promise((resolve) => {
let reader = new FileReader();
reader.readAsBinaryString(file); //以二进制的方式读取
reader.onload = (ev) => {
resolve(ev.target.result);
};
});
},
// 解析出表格表头
getHeader(sheet) {
// const XLSX = XLSX;
const headers = [];
const range = XLSX.utils.decode_range(sheet["!ref"]); // worksheet['!ref'] 是工作表的有效范围
let C;
/* 获取单元格值 start in the first row */
const R = range.s.r; // 行 // C 列
let i = 0;
for (C = range.s.c; C <= range.e.c; ++C) {
var cell =
sheet[
XLSX.utils.encode_cell({ c: C, r: R })
]; /* 根据地址得到单元格的值find the cell in the first row */
var hdr = "UNKNOWN" + C; // 如果有空表头,会替换为您想要的默认值replace with your desired default
// XLSX.utils.format_cell 生成单元格文本值
if (cell && cell.t) hdr = XLSX.utils.format_cell(cell);
if (hdr.indexOf("UNKNOWN") > -1) {
if (!i) {
hdr = "__EMPTY";
} else {
hdr = "__EMPTY_" + i;
}
i++;
}
headers.push(hdr);
}
// 保存至data中
this.excelHeader = headers;
return headers;
},
// 设置表格中英文映射
setTable() {
const headers = this.excelHeader;
const excellist = this.tableData;
const tableTitleData = []; // 存储表格表头数据
const tableMapTitle = {}; // 设置表格内容中英文对照用
headers.forEach((_, i) => {
tableMapTitle[_] = "prop" + i;
tableTitleData.push({
prop: "prop" + i,
label: _,
width: 100,
});
});
console.log("表格头标题:", tableTitleData);
// 映射表格内容属性名为英文
const newTableData = [];
excellist.forEach((_) => {
const newObj = {};
Object.keys(_).forEach((key) => {
newObj[tableMapTitle[key]] = _[key];
});
newTableData.push(newObj);
});
console.log("表格数据:", newTableData);
this.tableColumn = tableTitleData;
this.tableData = newTableData;
},
将表格导出为Excel的函数
== ‘fileName.xlsx’:==导出的文件名称,可自行设置
//导出表格为Excel
exportExcel() {
/* generate workbook object from table */
let xlsxParam = { raw: true } // 导出的内容只做解析,不进行格式转换
let table = document.querySelector('#excelTable').cloneNode(true)
//这里是双下划线
// table.removeChild(table.querySelector('.el-table__fixed'))
let wb = XLSX.utils.table_to_book(table, xlsxParam)
/* get binary string as output */
let wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: true, type: 'array' })
try {
FileSaver.saveAs(new Blob([wbout], { type: 'application/octet-stream' }), 'fileName.xlsx')
} catch (e) {
if (typeof console !== 'undefined') {
console.log(e, wbout)
}
}
return wbout
},
6、样式部分
<style lang='less' scoped>
.excelName {
display: flex;
justify-content: space-between;
font-size: 30px;
margin-bottom: 20px;
}
.imExcelBtn {
margin: 10px 0;
}
</style>
完整代码
<template>
<div id="Excel">
<!-- 上传 -->
<el-upload
action
accept=".xlsx, .xls"
:auto-upload="false"
:show-file-list="false"
:on-change="handle"
>
<el-button type="primary" class="imExcelBtn"
>导入Excel</el-button
>
</el-upload>
<!-- 表格名称及导出和关闭预览的按钮 -->
<div class="excelName" v-if="tableKey">
<div class="left"></div>
<div class="center">{{ excelName }}</div>
<div class="right">
<el-button type="success" @click="exportExcel">导出为Excel</el-button>
<el-button type="danger" @click="closeExcel">关闭预览</el-button>
</div>
</div>
<!-- 表格 -->
<el-table
:data="tableData"
style="width: 100%"
max-height="500"
:key="tableKey"
:header-cell-style="{
background: '#d2d28e',
color: '#000000',
}"
v-if="tableKey"
id="excelTable"
border
stripe
>
<!-- 第一个el-table-column 可根据需求删除-->
<el-table-column
header-align="center"
align="center"
type="index"
label="序号"
width="50"
></el-table-column>
<el-table-column
v-for="(item, index) in tableColumn"
:key="index"
:prop="item.prop"
:label="item.label"
width="width"
>
</el-table-column>
</el-table>
</div>
</template>
<script>
import * as XLSX from "xlsx/xlsx.mjs";
import FileSaver from "file-saver";
export default {
name: "Excel",
data() {
return {
tableKey: false, //表格的key及显示与隐藏
excelName: "", //excel表格名称
excelHeader: [], //excel的表头
tableData: [], //表格数据
tableColumn: [], //表格的表头
};
},
methods: {
readFile(file) {
//文件读取
return new Promise((resolve) => {
let reader = new FileReader();
reader.readAsBinaryString(file); //以二进制的方式读取
reader.onload = (ev) => {
resolve(ev.target.result);
};
});
},
// 上传文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
async handle(ev) {
//改变表格key值
this.tableKey = true;
let file = ev.raw;
this.excelName = file.name;
//截取表格文件名
this.excelName = this.excelName.substring(
0,
this.excelName.lastIndexOf(".")
);
console.log("上传的未解析源文件", file);
if (!file) {
console.log("文件打开失败");
return;
} else {
let data = await this.readFile(file);
let workbook = XLSX.read(data, { type: "binary" }); //解析二进制格式数据
console.log("二进制数据的解析:", workbook);
let worksheet = workbook.Sheets[workbook.SheetNames[0]]; //获取第一个Sheet
// 调用解析表头方法
this.getHeader(worksheet);
let result = XLSX.utils.sheet_to_json(worksheet); //转换为json数据格式
console.log("最终解析的 json 格式数据:", result);
this.tableData = result;
// 调用处理表头函数
this.setTable();
}
},
// 解析出表格表头
getHeader(sheet) {
// const XLSX = XLSX;
const headers = [];
const range = XLSX.utils.decode_range(sheet["!ref"]); // worksheet['!ref'] 是工作表的有效范围
let C;
/* 获取单元格值 start in the first row */
const R = range.s.r; // 行 // C 列
let i = 0;
for (C = range.s.c; C <= range.e.c; ++C) {
var cell =
sheet[
XLSX.utils.encode_cell({ c: C, r: R })
]; /* 根据地址得到单元格的值find the cell in the first row */
var hdr = "UNKNOWN" + C; // 如果有空表头,会替换为您想要的默认值replace with your desired default
// XLSX.utils.format_cell 生成单元格文本值
if (cell && cell.t) hdr = XLSX.utils.format_cell(cell);
if (hdr.indexOf("UNKNOWN") > -1) {
if (!i) {
hdr = "__EMPTY";
} else {
hdr = "__EMPTY_" + i;
}
i++;
}
headers.push(hdr);
}
// 保存至data中
this.excelHeader = headers;
return headers;
},
// 设置表格中英文映射
setTable() {
const headers = this.excelHeader;
const excellist = this.tableData;
const tableTitleData = []; // 存储表格表头数据
const tableMapTitle = {}; // 设置表格内容中英文对照用
headers.forEach((_, i) => {
tableMapTitle[_] = "prop" + i;
tableTitleData.push({
prop: "prop" + i,
label: _,
width: 100,
});
});
console.log("表格头标题:", tableTitleData);
// 映射表格内容属性名为英文
const newTableData = [];
excellist.forEach((_) => {
const newObj = {};
Object.keys(_).forEach((key) => {
newObj[tableMapTitle[key]] = _[key];
});
newTableData.push(newObj);
});
console.log("表格数据:", newTableData);
this.tableColumn = tableTitleData;
this.tableData = newTableData;
},
// 关闭表格预览
closeExcel() {
this.tableKey = false;
//表格数据置空
this.tableData = [];
this.tableColumn = [];
},
//导出表格为Excel
exportExcel() {
/* generate workbook object from table */
let xlsxParam = { raw: true } // 导出的内容只做解析,不进行格式转换
let table = document.querySelector('#excelTable').cloneNode(true)
//这里是双下划线
// table.removeChild(table.querySelector('.el-table__fixed'))
let wb = XLSX.utils.table_to_book(table, xlsxParam)
/* get binary string as output */
let wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: true, type: 'array' })
try {
FileSaver.saveAs(new Blob([wbout], { type: 'application/octet-stream' }), 'fileName.xlsx')
} catch (e) {
if (typeof console !== 'undefined') {
console.log(e, wbout)
}
}
return wbout
},
},
};
</script>
<style lang='less' scoped>
.excelName {
display: flex;
justify-content: space-between;
font-size: 30px;
margin-bottom: 20px;
}
.imExcelBtn {
margin: 10px 0;
}
</style>
导入部分参考文章:
Vue 前端解析 Excel 数据 从0-1超详细教你实现前端读取excel表格并渲染到界面
导出部分参考文章:
vue导出Excel——elementUI表格导出功能
|