当前位置:   article > 正文

前端解析包含图片的excel文件_前端如何解析excel带图片

前端如何解析excel带图片

一、前言

1、问题描述

有时候难免会遇到解析excel的情况,现在前端的很多插件都可以实现excel文件中文本内容的解析;但是很多时候excel文件中是带有图片文件的,这个图片文件的提取着实是让人有点头疼的;

本人查阅了很多资料,试了很多方法,结果都是以失败告终!

现决定使用一个迂回战术,完成一次曲线救国,哈哈哈,方法可能不太好,但勉强能够使用,如果有哪位大佬看见,还望指点迷津,跪谢~

2、excel文件

3、实现效果

二、实现思路

  • 第一步,使用XLSX插件,解析excel中的文本内容;
  • 第二步,使用JSZip插件,解析excel中的图片内容;
  • 第三步,将图片数据和文本数据进行整理,封装成我们最终需要的数据格式;

三、完整代码

  1. <template>
  2. <div class="container">
  3. <!-- 长传组件 -->
  4. <el-upload action="" :before-upload="beforeUpload" :http-request="() => {}">
  5. <el-button type="primary">导入excel</el-button>
  6. </el-upload>
  7. <!-- 表格组件 -->
  8. <el-table :data="tableData" border style="width: auto; margin-top: 10px">
  9. <el-table-column
  10. :prop="item"
  11. :label="item"
  12. align="center"
  13. v-for="(item, index) in tableColumnLabel"
  14. :key="index"
  15. >
  16. <template #default="scope" v-if="item == 'avatar'">
  17. <img :src="scope.row.avatar" alt="" style="width: 200px" />
  18. </template>
  19. </el-table-column>
  20. </el-table>
  21. </div>
  22. </template>
  23. <script setup>
  24. import { ref } from "vue";
  25. import JSZip from "jszip"; // 引入jszip
  26. import * as XLSX from "xlsx"; // 引入xlsx
  27. const tableColumnLabel = ref([]); // 获取表头内容
  28. const tableData = ref([]); // 表格数据
  29. const imageList = ref([]); // 表格图片
  30. // 加载按钮的回调
  31. async function beforeUpload(file) {
  32. // 解析图片
  33. imageList.value = await getExcelImage(file);
  34. // 解析数据
  35. getExcelData(file);
  36. }
  37. // 解析数据
  38. function getExcelData(file) {
  39. let fileReader = new FileReader(); // 构建fileReader对象
  40. fileReader.readAsArrayBuffer(file); // 读取指定文件内容
  41. // 读取操作完成时
  42. fileReader.onload = function (e) {
  43. try {
  44. let data = e.target.result; // 取得数据data
  45. // console.log(data);
  46. let workbook = XLSX.read(data, { type: "binary" }); // 将data转换成excel工作表数据
  47. // console.log("Excel工作簿", workbook);
  48. const worksheet = workbook.Sheets[workbook.SheetNames[0]]; // 获取第一个工作表
  49. // console.log("第一张工作表", worksheet);
  50. /*
  51. * XLSX.utils.sheet_to_json 输出JSON格式数据
  52. * 获取指定工作表中的数据sheetlist[],整个表中的数据存放在一个数组sheetlist中;
  53. * sheetlist数组中的每个元素均为一个数组rowlist,是每一行的数据;
  54. */
  55. const sheetlist = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
  56. //console.log('sheetlist', sheetlist);
  57. // 封装数据
  58. formatDate(sheetlist);
  59. } catch (e) {
  60. console.log("文件类型不正确");
  61. return;
  62. }
  63. };
  64. }
  65. // 封装数据
  66. function formatDate(sheetlist) {
  67. try {
  68. if (sheetlist.length < 1) return;
  69. tableColumnLabel.value = sheetlist[0]; // 获取表格列名
  70. for (let i = 0; i < sheetlist.length - 1; i++) {
  71. // 这里length-1是因为我们的sheetlist[0]为列名,实际的数据要少 1;
  72. let obj = {};
  73. for (let j = 0; j < sheetlist[0].length; j++) {
  74. // 头像列,则取解析到的imageList中的相应值;
  75. // 这里要求我们知道excel中存放图片的列名,否则会导致读取失败;
  76. if (sheetlist[0][j] == "avatar") {
  77. obj[sheetlist[0][j]] = `data:image/png;base64,${imageList.value[i]}`; // 注意base64编码的处理
  78. } else {
  79. // 非头像列,直接取值;
  80. obj[sheetlist[0][j]] = sheetlist[i + 1][j] ?? "";
  81. }
  82. }
  83. // console.log(obj);
  84. tableData.value.push(obj); // 添加到el-table绑定的数据源中
  85. }
  86. console.log("tableData.value", tableData.value);
  87. } catch (error) {
  88. console.log(error);
  89. return;
  90. }
  91. }
  92. // 获取图片
  93. async function getExcelImage(file) {
  94. // console.log(file);
  95. let imageList = []; // 用来存放图片
  96. const zip = new JSZip(); // 创建jszip实例
  97. try {
  98. let zipLoadResult = await zip.loadAsync(file); // 将xlsx文件转zip文件
  99. // console.log("zipLoadResult", zipLoadResult);
  100. for (const key in zipLoadResult["files"]) {
  101. // 遍历结果中的files对象
  102. if (key.indexOf("media/image") != -1 && !key.dir) {
  103. await zip
  104. .file(zipLoadResult["files"][key].name)
  105. .async("base64")
  106. .then((res) => {
  107. imageList.push(res); // 将解析出的图片的base64编码值 先存入imageList数组中;
  108. });
  109. }
  110. }
  111. } catch (error) {
  112. console.log(error);
  113. }
  114. // console.log('imageList', imageList);
  115. return imageList;
  116. }
  117. </script>
  118. <style lang="scss" scoped>
  119. </style>

四、准备工作

1、excel文件

先准备一个test.xlsx文件,内容如下图所示,主要带上图片就行;

2、上传组件

添加一个上传组件,用来上传excel文件;这里采用的是element-plus中的el-upload组件;

  1. <el-upload action="" :before-upload="beforeUpload" :http-request="() => {}">
  2. <el-button type="primary">导入excel</el-button>
  3. </el-upload>

这个上传组件并不是用来做上传,只是利用它来读取我们的excel文件;

后续我们将在beforeUpload()方法中处理导入的excel文件;

3、展示组件

添加一个数据展示组件,用来展示我们解析好的数据;这里采用的是el-table组件;

注意这里的列是动态生成的,如果是图片的列,则添加img标签显示图片; 

  1. <el-table :data="tableData" border style="width: auto; margin-top: 10px">
  2. <el-table-column :prop="item" :label="item" align="center" v-for="(item, index) in tableColumnLabel" :key="index">
  3. <template #default="scope" v-if="item == 'avatar'">
  4. <img :src="scope.row.avatar" alt="" style="width: 200px" />
  5. </template>
  6. </el-table-column>
  7. </el-table>

表格需要用到的数据; 

  1. import { ref } from "vue";
  2. const tableColumnLabel = ref([]); // 获取表头内容
  3. const tableData = ref([]); // 表格数据
  4. const imageList = ref([]); // 表格图片

4、安装依赖 

安装jszip依赖;

  1. npm install jszip
  2. yarn add jszip

安装xlsx依赖;

  1. npm install xlsx
  2. yarn xlsx

5、引入插件

在页面中引入需要用的jszip和xlsx两个依赖,可以使用其中的一些方法解析excel文件;

  1. import JSZip from "jszip";
  2. import * as XLSX from "xlsx";

6、现有效果 

到此,准备工作完成,现有代码与页面效果如下所示:

  1. <template>
  2. <div class="container">
  3. <!-- 长传组件 -->
  4. <el-upload action="" :before-upload="beforeUpload" :http-request="() => {}">
  5. <el-button type="primary">导入excel</el-button>
  6. </el-upload>
  7. <!-- 表格组件 -->
  8. <el-table :data="tableData" border style="width: auto; margin-top: 10px">
  9. <el-table-column :prop="item" :label="item" align="center" v-for="(item, index) in tableColumnLabel" :key="index">
  10. <template #default="scope" v-if="item == 'avatar'">
  11. <img :src="scope.row.avatar" alt="" style="width: 200px" />
  12. </template>
  13. </el-table-column>
  14. </el-table>
  15. </div>
  16. </template>
  17. <script setup>
  18. import { ref } from "vue";
  19. import JSZip from "jszip"; // 引入jszip
  20. import * as XLSX from "xlsx"; // 引入xlsx
  21. const tableColumnLabel = ref([]); // 获取表头内容
  22. const tableData = ref([]); // 表格数据
  23. const imageList = ref([]); // 表格图片
  24. // 加载按钮的回调
  25. function beforeUpload(file){
  26. console.log(file);
  27. }
  28. </script>
  29. <style lang="scss" scoped>
  30. </style>

 可以在页面看到一个导入按钮和一个没有任何数据的表格;

五、实现过程

1、加载excel

点击导入excel按钮,选择我们之前准备好的测试excel【test.xlsx】文件,

导入按钮的回调:

可以在控制台查看打印输出的结果:

到这里呢,表示我们的excel已经加载成功了,接下来继续解析读取到的内容即可;

2、解析图片文件

(1)解析思路

  • 使用jszip将xlsx文件转成zip文件;
  • 获取zip文件中的图片内容;
  • 将图片信息转base64编码存储;

解析图片文件我们需要用到jszip这个插件,至于为什么呢?因为我自己试了其他的方法都没有成功;

首先,我们先将【test.xlsx】转成【test.zip】文件;这里复制一份文件后 直接修改文件扩展名;压缩是看不到效果的;

点开这个【test.zip】文件,可以看到以下内容,

打开这个【xl】文件夹,在【media】下存放的是图片文件,worksheets下存放的是文本文件;

所以,我们想要获取excel中的图片文件,只需访问这个zip文件,然后获取其中【media】文件夹中的内容即可;

这个zip文件只是简单查看,有助于我们理解的,并没有解析的实际作用,后续删除即可;

(2)解析过程

  在beforeUpload()回调函数中,编写解析代码;

  1. // 加载按钮的回调
  2. async function beforeUpload(file){
  3. // console.log(file);
  4. let imageList = []; // 用来存放图片
  5. const zip = new JSZip(); // 创建jszip实例
  6. try {
  7. let zipLoadResult = await zip.loadAsync(file); // 将xlsx文件转zip文件
  8. console.log("zipLoadResult", zipLoadResult);
  9. // ......
  10. } catch (error) {
  11. console.log(error);
  12. }
  13. return imageList;
  14. }

在打印输出的结果中,我们可以看到跟之前自行手动转zip后的结果是一致的;图片文件在【xl/media】 路径文件夹中;

继续解析获取到的files对象,

  1. // 加载按钮的回调
  2. async function beforeUpload(file){
  3. // console.log(file);
  4. let imageList = []; // 用来存放图片
  5. const zip = new JSZip(); // 创建jszip实例
  6. try {
  7. let zipLoadResult = await zip.loadAsync(file); // 将xlsx文件转zip文件
  8. // console.log("zipLoadResult", zipLoadResult);
  9. for (const key in zipLoadResult["files"]) { // 遍历结果中的files对象
  10. if (key.indexOf("media/image") != -1 && !key.dir) {
  11. await zip
  12. .file(zipLoadResult["files"][key].name)
  13. .async("base64")
  14. .then((res) => {
  15. imageList.push(res); // 将解析出的图片的base64编码值 先存入imageList数组中;
  16. });
  17. }
  18. }
  19. } catch (error) {
  20. console.log(error);
  21. }
  22. console.log('imageList', imageList);
  23. return imageList;
  24. }

可以看到已经成功获取到了两个图片的base64编码值;

在下方链接中,可以检测取到的bae64是否正确:

在线Base64转图片

到此,我们已经取到了excel文件中的图片信息imageList!!

最后,我们将这段解析excel中图片的代码进行封装,后续在其他地方也可以使用;

  1. // 加载按钮的回调
  2. async function beforeUpload(file){
  3. // 解析图片
  4. imageList.value = await getExcelImage(file);
  5. }
  6. // 获取图片
  7. async function getExcelImage(file){
  8. // console.log(file);
  9. let imageList = []; // 用来存放图片
  10. const zip = new JSZip(); // 创建jszip实例
  11. try {
  12. let zipLoadResult = await zip.loadAsync(file); // 将xlsx文件转zip文件
  13. // console.log("zipLoadResult", zipLoadResult);
  14. for (const key in zipLoadResult["files"]) { // 遍历结果中的files对象
  15. if (key.indexOf("media/image") != -1 && !key.dir) {
  16. await zip
  17. .file(zipLoadResult["files"][key].name)
  18. .async("base64")
  19. .then((res) => {
  20. imageList.push(res); // 将解析出的图片的base64编码值 先存入imageList数组中;
  21. });
  22. }
  23. }
  24. } catch (error) {
  25. console.log(error);
  26. }
  27. // console.log('imageList', imageList);
  28. return imageList;
  29. }

3、解析文本内容

(1)解析思路

  • 使用FileReader对象来读取excel文件数据data;
  • 使用xlsx获取excel表格数据;
  • 封装sheetlist数据为el-table绑定的数据格式;

(2)解析过程

首先,查看FileReader的读取结果;

  1. async function beforeUpload(file){
  2. // 解析图片
  3. imageList.value = await getExcelImage(file);
  4. // ==================================================================================== //
  5. // 解析数据
  6. let fileReader = new FileReader(); // 构建fileReader对象
  7. fileReader.readAsArrayBuffer(file); // 读取指定文件内容
  8. // 读取操作完成时
  9. fileReader.onload = function (e) {
  10. try {
  11. console.log('data', e);
  12. // ......
  13. } catch (e) {
  14. console.log("文件类型不正确");
  15. return;
  16. }
  17. };
  18. }

其次,使用XLSX.utils.sheet_to_json(worksheet, { header: 1 })方法,处理FileReader读取到的数据data;

该方法的第一个参数woksheet是必须要传的,值为工作表数据;

第二个参数可选,用于指定输出excel的格式;

  1. // 加载按钮的回调
  2. async function beforeUpload(file){
  3. // 解析图片
  4. imageList.value = await getExcelImage(file);
  5. // ==================================================================================== //
  6. // 解析数据
  7. let fileReader = new FileReader(); // 构建fileReader对象
  8. fileReader.readAsArrayBuffer(file); // 读取指定文件内容
  9. // 读取操作完成时
  10. fileReader.onload = function (e) {
  11. try {
  12. let data = e.target.result; // 取得数据data
  13. // console.log(data);
  14. let workbook = XLSX.read(data, { type: "binary" }); // 将data转换成excel工作表数据
  15. // console.log("Excel工作簿", workbook);
  16. const worksheet = workbook.Sheets[workbook.SheetNames[0]]; // 获取第一个工作表
  17. // console.log("第一张工作表", worksheet);
  18. /*
  19. * XLSX.utils.sheet_to_json 输出JSON格式数据
  20. * 获取指定工作表中的数据sheetlist[],整个表中的数据存放在一个数组sheetlist中;
  21. * sheetlist数组中的每个元素均为一个数组rowlist,是每一行的数据;
  22. */
  23. const sheetlist = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
  24. console.log(sheetlist,'sheetlist');
  25. } catch (e) {
  26. console.log("文件类型不正确");
  27. return;
  28. }
  29. };
  30. }

到此为止,我们已经获取到了excel中的文本数据sheetlist,可以在控制台查看如下所示结果;

外层是一个数组[ ],存放整个excel中的文本数据;

其中的每个元素均为一个数组[ ],存放的是每一行的数据;

 最后,我们将这段解析excel中文本的代码进行抽离;

  1. // 加载按钮的回调
  2. async function beforeUpload(file){
  3. // 解析图片
  4. imageList.value = await getExcelImage(file);
  5. // 解析数据
  6. getExcelData(file);
  7. }
  8. // 解析数据
  9. function getExcelData(file) {
  10. let fileReader = new FileReader(); // 构建fileReader对象
  11. fileReader.readAsArrayBuffer(file); // 读取指定文件内容
  12. // 读取操作完成时
  13. fileReader.onload = function (e) {
  14. try {
  15. let data = e.target.result; // 取得数据data
  16. // console.log(data);
  17. let workbook = XLSX.read(data, { type: "binary" }); // 将data转换成excel工作表数据
  18. // console.log("Excel工作簿", workbook);
  19. const worksheet = workbook.Sheets[workbook.SheetNames[0]]; // 获取第一个工作表
  20. // console.log("第一张工作表", worksheet);
  21. /*
  22. * XLSX.utils.sheet_to_json 输出JSON格式数据
  23. * 获取指定工作表中的数据sheetlist[],整个表中的数据存放在一个数组sheetlist中;
  24. * sheetlist数组中的每个元素均为一个数组rowlist,是每一行的数据;
  25. */
  26. const sheetlist = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
  27. // console.log('sheetlist', sheetlist);
  28. } catch (e) {
  29. console.log("文件类型不正确");
  30. return;
  31. }
  32. };
  33. }

4、封装数据 

根据上述内容,excel文件中的图片和文本内容均已取得,如何封装称自己想要的数据格式,可以自行解决了;这里给出我自己在el-table中需要的数据格式封装方法;

(1)封装思路

获取到的sheetlist的数据格式如下:

  1. sheetlist = [
  2. ["name", "age", "avatar"],
  3. ["张三", 18],
  4. ["李四", 20],
  5. ]

这并不是我们想要的,期望的格式应该是如下所示:

最外层是一个数组[ ],里面是每个数据对象itemObj;

  1. [
  2. {
  3. name:'张三',
  4. age:18,
  5. avatar:"imageUrl"
  6. },
  7. {
  8. name:'李四',
  9. age:20,
  10. avatar:"imageUrl"
  11. },
  12. ]
  • 首先,我们可以看出sheetlist[0],就是我们想要的el-table的列名;
  • 其次,使用双重循环拆解重组数据;

        创建一个对象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]};

  • 最后,将新建的obj对象push进el-table绑定的数据源中即可看到结果了;

(2)实现过程

我们编写一个封装数据的方法,并在解析好excel的文本数据后调用它;

获取el-table的列名;

  1. // 封装数据
  2. function formatDate(sheetlist) {
  3. tableColumnLabel.value = sheetlist[0]; // 获取表格列名
  4. }

此时,页面上已经有了显示效果;

使用双重循环拆解组合数据,这里不做过多解释,大家可以自己写个方法,能够让我参考参考,感觉自己写的也不怎么好;

  1. // 封装数据
  2. function formatDate(sheetlist) {
  3. tableColumnLabel.value = sheetlist[0]; // 获取表格列名
  4. for (let i = 0; i < sheetlist.length - 1; i++) {
  5. let obj = {};
  6. for (let j = 0; j < sheetlist[0].length; j++) {
  7. // 头像列,则取解析到的imageList中的相应值;
  8. // 这里要求我们知道excel中存放图片的列名,否则会导致读取失败;
  9. if (sheetlist[0][j] == "avatar") {
  10. obj[sheetlist[0][j]] = `data:image/png;base64,${imageList.value[i]}`; // 注意base64编码的处理
  11. } else { // 非头像列,直接取值;
  12. obj[sheetlist[0][j]] = sheetlist[i + 1][j] ?? "";
  13. }
  14. }
  15. console.log(obj);
  16. }
  17. }

 可以在控制台查看每个obj对象的输出结果;

 最后,将这个obj对象push进el-table绑定的数据源中;

  1. // 封装数据
  2. function formatDate(sheetlist) {
  3. tableColumnLabel.value = sheetlist[0]; // 获取表格列名
  4. for (let i = 0; i < sheetlist.length - 1; i++) { // 这里length-1是因为我们的sheetlist[0]为列名,实际的数据要少 1;
  5. let obj = {};
  6. for (let j = 0; j < sheetlist[0].length; j++) {
  7. // 头像列,则取解析到的imageList中的相应值;
  8. // 这里要求我们知道excel中存放图片的列名,否则会导致读取失败;
  9. if (sheetlist[0][j] == "avatar") {
  10. obj[sheetlist[0][j]] = `data:image/png;base64,${imageList.value[i]}`; // 注意base64编码的处理
  11. } else { // 非头像列,直接取值;
  12. obj[sheetlist[0][j]] = sheetlist[i + 1][j] ?? "";
  13. }
  14. }
  15. // console.log(obj);
  16. tableData.value.push(obj); // 添加到el-table绑定的数据源中
  17. }
  18. console.log("tableData.value", tableData.value);
  19. }

 控制台查看打印输出结果;

页面最终显示效果;

5、现有问题

第一,采取这个方法的前提是得明确知道excel中存放图片的列名;

第二,图片是按照在excel中的顺序加载的,存在较多未知的隐患;

第三,谨慎使用!谨慎使用!谨慎使用!

======================================================================================================================

每天进步一点点,本文就做一个简单记录吧~

暂时也没有更好的方法去读取excel,先这样完成就行;

谢谢大家,还望哪位大佬指点指点!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/748248
推荐阅读
相关标签
  

闽ICP备14008679号