赞
踩
有时候难免会遇到解析excel的情况,现在前端的很多插件都可以实现excel文件中文本内容的解析;但是很多时候excel文件中是带有图片文件的,这个图片文件的提取着实是让人有点头疼的;
本人查阅了很多资料,试了很多方法,结果都是以失败告终!
现决定使用一个迂回战术,完成一次曲线救国,哈哈哈,方法可能不太好,但勉强能够使用,如果有哪位大佬看见,还望指点迷津,跪谢~
- <template>
- <div class="container">
- <!-- 长传组件 -->
- <el-upload action="" :before-upload="beforeUpload" :http-request="() => {}">
- <el-button type="primary">导入excel</el-button>
- </el-upload>
-
- <!-- 表格组件 -->
- <el-table :data="tableData" border style="width: auto; margin-top: 10px">
- <el-table-column
- :prop="item"
- :label="item"
- align="center"
- v-for="(item, index) in tableColumnLabel"
- :key="index"
- >
- <template #default="scope" v-if="item == 'avatar'">
- <img :src="scope.row.avatar" alt="" style="width: 200px" />
- </template>
- </el-table-column>
- </el-table>
- </div>
- </template>
- <script setup>
- import { ref } from "vue";
-
- import JSZip from "jszip"; // 引入jszip
- import * as XLSX from "xlsx"; // 引入xlsx
-
- const tableColumnLabel = ref([]); // 获取表头内容
- const tableData = ref([]); // 表格数据
- const imageList = ref([]); // 表格图片
-
- // 加载按钮的回调
- async function beforeUpload(file) {
- // 解析图片
- imageList.value = await getExcelImage(file);
-
- // 解析数据
- getExcelData(file);
- }
-
- // 解析数据
- function getExcelData(file) {
- let fileReader = new FileReader(); // 构建fileReader对象
-
- fileReader.readAsArrayBuffer(file); // 读取指定文件内容
-
- // 读取操作完成时
- fileReader.onload = function (e) {
- try {
- let data = e.target.result; // 取得数据data
- // console.log(data);
-
- let workbook = XLSX.read(data, { type: "binary" }); // 将data转换成excel工作表数据
- // console.log("Excel工作簿", workbook);
-
- const worksheet = workbook.Sheets[workbook.SheetNames[0]]; // 获取第一个工作表
- // console.log("第一张工作表", worksheet);
-
- /*
- * XLSX.utils.sheet_to_json 输出JSON格式数据
- * 获取指定工作表中的数据sheetlist[],整个表中的数据存放在一个数组sheetlist中;
- * sheetlist数组中的每个元素均为一个数组rowlist,是每一行的数据;
- */
- const sheetlist = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
- //console.log('sheetlist', sheetlist);
-
- // 封装数据
- formatDate(sheetlist);
- } catch (e) {
- console.log("文件类型不正确");
- return;
- }
- };
- }
-
- // 封装数据
- function formatDate(sheetlist) {
- try {
- if (sheetlist.length < 1) return;
- tableColumnLabel.value = sheetlist[0]; // 获取表格列名
-
- for (let i = 0; i < sheetlist.length - 1; i++) {
- // 这里length-1是因为我们的sheetlist[0]为列名,实际的数据要少 1;
- let obj = {};
- for (let j = 0; j < sheetlist[0].length; j++) {
- // 头像列,则取解析到的imageList中的相应值;
- // 这里要求我们知道excel中存放图片的列名,否则会导致读取失败;
- if (sheetlist[0][j] == "avatar") {
- obj[sheetlist[0][j]] = `data:image/png;base64,${imageList.value[i]}`; // 注意base64编码的处理
- } else {
- // 非头像列,直接取值;
- obj[sheetlist[0][j]] = sheetlist[i + 1][j] ?? "";
- }
- }
- // console.log(obj);
- tableData.value.push(obj); // 添加到el-table绑定的数据源中
- }
- console.log("tableData.value", tableData.value);
- } catch (error) {
- console.log(error);
- return;
- }
- }
-
- // 获取图片
- async function getExcelImage(file) {
- // console.log(file);
-
- let imageList = []; // 用来存放图片
- const zip = new JSZip(); // 创建jszip实例
-
- try {
- let zipLoadResult = await zip.loadAsync(file); // 将xlsx文件转zip文件
- // console.log("zipLoadResult", zipLoadResult);
-
- for (const key in zipLoadResult["files"]) {
- // 遍历结果中的files对象
-
- if (key.indexOf("media/image") != -1 && !key.dir) {
- await zip
- .file(zipLoadResult["files"][key].name)
- .async("base64")
- .then((res) => {
- imageList.push(res); // 将解析出的图片的base64编码值 先存入imageList数组中;
- });
- }
- }
- } catch (error) {
- console.log(error);
- }
- // console.log('imageList', imageList);
- return imageList;
- }
- </script>
- <style lang="scss" scoped>
- </style>
先准备一个test.xlsx文件,内容如下图所示,主要带上图片就行;
添加一个上传组件,用来上传excel文件;这里采用的是element-plus中的el-upload组件;
- <el-upload action="" :before-upload="beforeUpload" :http-request="() => {}">
- <el-button type="primary">导入excel</el-button>
- </el-upload>
这个上传组件并不是用来做上传,只是利用它来读取我们的excel文件;
后续我们将在beforeUpload()方法中处理导入的excel文件;
添加一个数据展示组件,用来展示我们解析好的数据;这里采用的是el-table组件;
注意这里的列是动态生成的,如果是图片的列,则添加img标签显示图片;
- <el-table :data="tableData" border style="width: auto; margin-top: 10px">
- <el-table-column :prop="item" :label="item" align="center" v-for="(item, index) in tableColumnLabel" :key="index">
- <template #default="scope" v-if="item == 'avatar'">
- <img :src="scope.row.avatar" alt="" style="width: 200px" />
- </template>
- </el-table-column>
- </el-table>
表格需要用到的数据;
- import { ref } from "vue";
- const tableColumnLabel = ref([]); // 获取表头内容
- const tableData = ref([]); // 表格数据
- const imageList = ref([]); // 表格图片
安装jszip依赖;
- npm install jszip
-
- 或
-
- yarn add jszip
安装xlsx依赖;
- npm install xlsx
-
- 或
-
- yarn xlsx
在页面中引入需要用的jszip和xlsx两个依赖,可以使用其中的一些方法解析excel文件;
- import JSZip from "jszip";
- import * as XLSX from "xlsx";
到此,准备工作完成,现有代码与页面效果如下所示:
- <template>
- <div class="container">
-
- <!-- 长传组件 -->
- <el-upload action="" :before-upload="beforeUpload" :http-request="() => {}">
- <el-button type="primary">导入excel</el-button>
- </el-upload>
-
- <!-- 表格组件 -->
- <el-table :data="tableData" border style="width: auto; margin-top: 10px">
- <el-table-column :prop="item" :label="item" align="center" v-for="(item, index) in tableColumnLabel" :key="index">
- <template #default="scope" v-if="item == 'avatar'">
- <img :src="scope.row.avatar" alt="" style="width: 200px" />
- </template>
- </el-table-column>
- </el-table>
-
- </div>
- </template>
- <script setup>
- import { ref } from "vue";
-
- import JSZip from "jszip"; // 引入jszip
- import * as XLSX from "xlsx"; // 引入xlsx
-
- const tableColumnLabel = ref([]); // 获取表头内容
- const tableData = ref([]); // 表格数据
- const imageList = ref([]); // 表格图片
-
- // 加载按钮的回调
- function beforeUpload(file){
- console.log(file);
- }
-
- </script>
- <style lang="scss" scoped>
- </style>
可以在页面看到一个导入按钮和一个没有任何数据的表格;
点击导入excel按钮,选择我们之前准备好的测试excel【test.xlsx】文件,
导入按钮的回调:
可以在控制台查看打印输出的结果:
到这里呢,表示我们的excel已经加载成功了,接下来继续解析读取到的内容即可;
解析图片文件我们需要用到jszip这个插件,至于为什么呢?因为我自己试了其他的方法都没有成功;
首先,我们先将【test.xlsx】转成【test.zip】文件;这里复制一份文件后 直接修改文件扩展名;压缩是看不到效果的;
点开这个【test.zip】文件,可以看到以下内容,
打开这个【xl】文件夹,在【media】下存放的是图片文件,worksheets下存放的是文本文件;
所以,我们想要获取excel中的图片文件,只需访问这个zip文件,然后获取其中【media】文件夹中的内容即可;
这个zip文件只是简单查看,有助于我们理解的,并没有解析的实际作用,后续删除即可;
在beforeUpload()回调函数中,编写解析代码;
- // 加载按钮的回调
- async function beforeUpload(file){
- // console.log(file);
-
- let imageList = []; // 用来存放图片
- const zip = new JSZip(); // 创建jszip实例
-
- try {
-
- let zipLoadResult = await zip.loadAsync(file); // 将xlsx文件转zip文件
- console.log("zipLoadResult", zipLoadResult);
-
- // ......
-
- } catch (error) {
- console.log(error);
- }
- return imageList;
- }
在打印输出的结果中,我们可以看到跟之前自行手动转zip后的结果是一致的;图片文件在【xl/media】 路径文件夹中;
继续解析获取到的files对象,
- // 加载按钮的回调
- async function beforeUpload(file){
- // console.log(file);
-
- let imageList = []; // 用来存放图片
- const zip = new JSZip(); // 创建jszip实例
-
- try {
- let zipLoadResult = await zip.loadAsync(file); // 将xlsx文件转zip文件
- // console.log("zipLoadResult", zipLoadResult);
-
- for (const key in zipLoadResult["files"]) { // 遍历结果中的files对象
-
- if (key.indexOf("media/image") != -1 && !key.dir) {
- await zip
- .file(zipLoadResult["files"][key].name)
- .async("base64")
- .then((res) => {
- imageList.push(res); // 将解析出的图片的base64编码值 先存入imageList数组中;
- });
- }
-
- }
-
- } catch (error) {
- console.log(error);
- }
- console.log('imageList', imageList);
- return imageList;
- }
可以看到已经成功获取到了两个图片的base64编码值;
在下方链接中,可以检测取到的bae64是否正确:
到此,我们已经取到了excel文件中的图片信息imageList!!
最后,我们将这段解析excel中图片的代码进行封装,后续在其他地方也可以使用;
- // 加载按钮的回调
- async function beforeUpload(file){
- // 解析图片
- imageList.value = await getExcelImage(file);
- }
-
- // 获取图片
- async function getExcelImage(file){
- // console.log(file);
-
- let imageList = []; // 用来存放图片
- const zip = new JSZip(); // 创建jszip实例
-
- try {
- let zipLoadResult = await zip.loadAsync(file); // 将xlsx文件转zip文件
- // console.log("zipLoadResult", zipLoadResult);
-
- for (const key in zipLoadResult["files"]) { // 遍历结果中的files对象
-
- if (key.indexOf("media/image") != -1 && !key.dir) {
- await zip
- .file(zipLoadResult["files"][key].name)
- .async("base64")
- .then((res) => {
- imageList.push(res); // 将解析出的图片的base64编码值 先存入imageList数组中;
- });
- }
-
- }
-
- } catch (error) {
- console.log(error);
- }
- // console.log('imageList', imageList);
- return imageList;
- }
首先,查看FileReader的读取结果;
- async function beforeUpload(file){
- // 解析图片
- imageList.value = await getExcelImage(file);
-
- // ==================================================================================== //
- // 解析数据
- let fileReader = new FileReader(); // 构建fileReader对象
-
- fileReader.readAsArrayBuffer(file); // 读取指定文件内容
-
- // 读取操作完成时
- fileReader.onload = function (e) {
- try {
- console.log('data', e);
-
- // ......
-
- } catch (e) {
- console.log("文件类型不正确");
- return;
- }
- };
- }
其次,使用XLSX.utils.sheet_to_json(worksheet, { header: 1 })方法,处理FileReader读取到的数据data;
该方法的第一个参数woksheet是必须要传的,值为工作表数据;
第二个参数可选,用于指定输出excel的格式;
- // 加载按钮的回调
- async function beforeUpload(file){
- // 解析图片
- imageList.value = await getExcelImage(file);
-
- // ==================================================================================== //
- // 解析数据
- let fileReader = new FileReader(); // 构建fileReader对象
-
- fileReader.readAsArrayBuffer(file); // 读取指定文件内容
-
- // 读取操作完成时
- fileReader.onload = function (e) {
- try {
- let data = e.target.result; // 取得数据data
- // console.log(data);
-
- let workbook = XLSX.read(data, { type: "binary" }); // 将data转换成excel工作表数据
- // console.log("Excel工作簿", workbook);
-
- const worksheet = workbook.Sheets[workbook.SheetNames[0]]; // 获取第一个工作表
- // console.log("第一张工作表", worksheet);
-
- /*
- * XLSX.utils.sheet_to_json 输出JSON格式数据
- * 获取指定工作表中的数据sheetlist[],整个表中的数据存放在一个数组sheetlist中;
- * sheetlist数组中的每个元素均为一个数组rowlist,是每一行的数据;
- */
- const sheetlist = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
- console.log(sheetlist,'sheetlist');
-
- } catch (e) {
- console.log("文件类型不正确");
- return;
- }
- };
- }
到此为止,我们已经获取到了excel中的文本数据sheetlist,可以在控制台查看如下所示结果;
外层是一个数组[ ],存放整个excel中的文本数据;
其中的每个元素均为一个数组[ ],存放的是每一行的数据;
最后,我们将这段解析excel中文本的代码进行抽离;
- // 加载按钮的回调
- async function beforeUpload(file){
- // 解析图片
- imageList.value = await getExcelImage(file);
-
- // 解析数据
- getExcelData(file);
- }
-
- // 解析数据
- function getExcelData(file) {
-
- let fileReader = new FileReader(); // 构建fileReader对象
-
- fileReader.readAsArrayBuffer(file); // 读取指定文件内容
-
- // 读取操作完成时
- fileReader.onload = function (e) {
- try {
- let data = e.target.result; // 取得数据data
- // console.log(data);
-
- let workbook = XLSX.read(data, { type: "binary" }); // 将data转换成excel工作表数据
- // console.log("Excel工作簿", workbook);
-
- const worksheet = workbook.Sheets[workbook.SheetNames[0]]; // 获取第一个工作表
- // console.log("第一张工作表", worksheet);
-
- /*
- * XLSX.utils.sheet_to_json 输出JSON格式数据
- * 获取指定工作表中的数据sheetlist[],整个表中的数据存放在一个数组sheetlist中;
- * sheetlist数组中的每个元素均为一个数组rowlist,是每一行的数据;
- */
- const sheetlist = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
- // console.log('sheetlist', sheetlist);
-
- } catch (e) {
- console.log("文件类型不正确");
- return;
- }
- };
- }
根据上述内容,excel文件中的图片和文本内容均已取得,如何封装称自己想要的数据格式,可以自行解决了;这里给出我自己在el-table中需要的数据格式封装方法;
获取到的sheetlist的数据格式如下:
- sheetlist = [
- ["name", "age", "avatar"],
- ["张三", 18],
- ["李四", 20],
- ]
这并不是我们想要的,期望的格式应该是如下所示:
最外层是一个数组[ ],里面是每个数据对象itemObj;
- [
- {
- name:'张三',
- age:18,
- avatar:"imageUrl"
- },
- {
- name:'李四',
- age:20,
- avatar:"imageUrl"
- },
- ]
创建一个对象obj,在我们取到sheetlist[0][0],也就是“name”的时候,让obj[“name”] = “张三”,obj[“age”] = “18”,obj[“avatar”] = “”,也就是obj[sheetlist[0][0]] = sheetlist[1][0]、obj[sheetlist[0][1]] = sheetlist[1][1],obj[sheetlist[0][2]] = sheetlist[1][2],以此类推...;
这里,刚刚好在给obj[“avatar”] = “”赋值的时候我们可以赋值成imagelist中的值,也就是obj[sheetlist[0][2]] = imagelist[i];注意,imagelist中存储的是base64编码值,别忘记赋值之前进行编码转换,obj[sheetlist[0][2]] = `data:image/png;base64,${imageList.value[i]};
我们编写一个封装数据的方法,并在解析好excel的文本数据后调用它;
获取el-table的列名;
- // 封装数据
- function formatDate(sheetlist) {
- tableColumnLabel.value = sheetlist[0]; // 获取表格列名
- }
此时,页面上已经有了显示效果;
使用双重循环拆解组合数据,这里不做过多解释,大家可以自己写个方法,能够让我参考参考,感觉自己写的也不怎么好;
- // 封装数据
- function formatDate(sheetlist) {
- tableColumnLabel.value = sheetlist[0]; // 获取表格列名
-
- for (let i = 0; i < sheetlist.length - 1; i++) {
- let obj = {};
- for (let j = 0; j < sheetlist[0].length; j++) {
-
- // 头像列,则取解析到的imageList中的相应值;
- // 这里要求我们知道excel中存放图片的列名,否则会导致读取失败;
- if (sheetlist[0][j] == "avatar") {
- obj[sheetlist[0][j]] = `data:image/png;base64,${imageList.value[i]}`; // 注意base64编码的处理
- } else { // 非头像列,直接取值;
- obj[sheetlist[0][j]] = sheetlist[i + 1][j] ?? "";
- }
- }
- console.log(obj);
- }
- }
可以在控制台查看每个obj对象的输出结果;
最后,将这个obj对象push进el-table绑定的数据源中;
- // 封装数据
- function formatDate(sheetlist) {
- tableColumnLabel.value = sheetlist[0]; // 获取表格列名
-
- for (let i = 0; i < sheetlist.length - 1; i++) { // 这里length-1是因为我们的sheetlist[0]为列名,实际的数据要少 1;
- let obj = {};
- for (let j = 0; j < sheetlist[0].length; j++) {
-
- // 头像列,则取解析到的imageList中的相应值;
- // 这里要求我们知道excel中存放图片的列名,否则会导致读取失败;
- if (sheetlist[0][j] == "avatar") {
- obj[sheetlist[0][j]] = `data:image/png;base64,${imageList.value[i]}`; // 注意base64编码的处理
- } else { // 非头像列,直接取值;
- obj[sheetlist[0][j]] = sheetlist[i + 1][j] ?? "";
- }
- }
- // console.log(obj);
- tableData.value.push(obj); // 添加到el-table绑定的数据源中
- }
- console.log("tableData.value", tableData.value);
- }
控制台查看打印输出结果;
页面最终显示效果;
第一,采取这个方法的前提是得明确知道excel中存放图片的列名;
第二,图片是按照在excel中的顺序加载的,存在较多未知的隐患;
第三,谨慎使用!谨慎使用!谨慎使用!
======================================================================================================================
每天进步一点点,本文就做一个简单记录吧~
暂时也没有更好的方法去读取excel,先这样完成就行;
谢谢大家,还望哪位大佬指点指点!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。