• vue中或者react中的excel导入和导出


    excel导入和导出是后台管理系统常见的功能。

           当我们把信息化系统给用户使用时,用户经常需要把以前在excel里录入的数据导入的信息化系统里,这样为用户提供了很大的方便。

            在用户使用信息化系统时,也需要把网页表格里的数据导出到excel里,方便进行打印,排版等等。

    一、安装依赖的模块:

    1、file-saver 用于文件操作

    2、xlsx用于excel文件处

    npm i xlsx@0.17.0 -S
    
    npm i file-saver@2.0.5 -S

    二、导出功能实现

    在自己的项目中新建一个js文件模块。放入如下代码:

    1、使用dom元素导出
    1. // 1、根据dom元素导出成excel文件:
    2. // 自动分析dom元素导出excel
    3. // 参数:
    4. // table:表格的dom元素对象
    5. // filename:导出的文件名(不用写扩展名)
    6. export function excelExport(table, filename) {
    7. // workbook,
    8. const wb = XLSX.utils.table_to_book(table);
    9. console.log("wb", wb);
    10. /* Export to file (start a download) */
    11. const defaultCellStyle = {
    12. font: { name: 'Verdana', sz: 13, color: 'FF00FF88' },
    13. fill: { fgColor: { rgb: 'FFFFAA00' } },
    14. }
    15. const wopts = {
    16. bookType: 'xlsx',
    17. bookSST: false,
    18. type: 'binary',
    19. cellStyle: true,
    20. defaultCellStyle: defaultCellStyle,
    21. showGridLines: false,
    22. }
    23. const wbout = XLSX.write(wb, wopts)
    24. const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' })
    25. saveAs(blob, filename + '.xlsx')
    26. }
    27. function s2ab(s) {
    28. console.log("s", s);
    29. var buf = new ArrayBuffer(s.length);
    30. var view = new Uint8Array(buf);
    31. for (var i = 0; i != s.length; ++i) {
    32. view[i] = s.charCodeAt(i) & 0xFF;
    33. }
    34. return buf;
    35. }

    调用示例:

    excelExport(document.getElementById("t2"), "student");// t2是一个table标签的id。其实是包含表格标签的id,会自动分析的。
    2、使用json数组数据导出
    1. // 2、根据json数据(数组)导出成excel文件:
    2. // 参数:
    3. // data:json数组
    4. // headers:excel的表头
    5. // filename:导出的文件名(不用写扩展名)
    6. export function excelExportUseJson(data, headers, filename) {
    7. // 使用深克隆不影响原table数据的展示
    8. const json = cloneDeep(data)
    9. json.forEach(item => {
    10. for (let key in item) {
    11. if (headers.hasOwnProperty(key)) {
    12. item[headers[key]] = item[key]
    13. }
    14. delete item[key]
    15. }
    16. })
    17. // excel 对象
    18. const wb = XLSX.utils.book_new()
    19. // 创建sheet
    20. const ws = XLSX.utils.json_to_sheet(json, { header: Object.values(headers) })
    21. // excel 添加sheet名称
    22. wb.SheetNames.push(filename)
    23. // excel 添加sheet
    24. wb.Sheets[filename] = ws
    25. const defaultCellStyle = {
    26. font: { name: 'Verdana', sz: 13, color: 'FF00FF88' },
    27. fill: { fgColor: { rgb: 'FFFFAA00' } },
    28. }
    29. const wopts = {
    30. bookType: 'xlsx',
    31. bookSST: false,
    32. type: 'binary',
    33. cellStyle: true,
    34. defaultCellStyle: defaultCellStyle,
    35. showGridLines: false,
    36. }
    37. const wbout = XLSX.write(wb, wopts)
    38. const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' })
    39. saveAs(blob, filename + '.xlsx')
    40. }
    41. function cloneDeep(obj) {
    42. if (typeof obj !== 'object' || obj === null) {
    43. return obj;
    44. }
    45. let clonedObj = Array.isArray(obj) ? [] : {};
    46. for (let key in obj) {
    47. if (obj.hasOwnProperty(key)) {
    48. clonedObj[key] = cloneDeep(obj[key]);
    49. }
    50. }
    51. return clonedObj;
    52. }

    调用示例:
     

    1. 调用示例:
    2. const books = [
    3. ​ {
    4. ​ id:"878911",
    5. ​ name:"三国演义"
    6. ​ },
    7. ​ {
    8. ​ id:"878912",
    9. ​ name:"西游记"
    10. ​ }
    11. ]
    12. excelExportUseJson(books,{id:"编号",name:"书名"},"student02");

    三、导入功能实现

    1. // 1、导入成dom元素:
    2. // 参数:
    3. // data:文件对象(用<input type=file /> 选择到file对象
    4. // domId:导入的excel显示的容器
    5. export function httpRequestToHTML(data, domId) {
    6. const file = data
    7. const types = file.name.split('.')[1]
    8. const fileType = ['xlsx', 'xlc', 'xlm', 'xls', 'xlt'].some(
    9. (item) => item === types
    10. )
    11. if (!fileType) {
    12. this.$message.error('格式错误!请重新选择')
    13. return
    14. }
    15. const reader = new FileReader()
    16. reader.readAsArrayBuffer(file, 'utf-8');
    17. return new Promise(function (resolve, reject) {
    18. reader.onloadend = function (e) {
    19. const data = e.target.result
    20. console.log('data', data)
    21. const wb = XLSX.read(data, {
    22. type: 'buffer'
    23. })
    24. const ws = wb.Sheets[wb.SheetNames[0]]
    25. console.log('ws', ws)
    26. const htmlStr = XLSX.utils.sheet_to_html(ws)
    27. resolve(htmlStr);
    28. }
    29. });
    30. }
    31. // 2、导入成json数据。
    32. // 参数:
    33. // data:文件对象(用<input type=file /> 选择到file对象
    34. export function httpRequestToJSON(data) {
    35. const file = data
    36. const types = file.name.split('.')[1]
    37. const fileType = ['xlsx', 'xlc', 'xlm', 'xls', 'xlt'].some(
    38. (item) => item === types
    39. )
    40. if (!fileType) {
    41. this.$message.error('格式错误!请重新选择')
    42. return
    43. }
    44. const reader = new FileReader()
    45. reader.readAsArrayBuffer(file, 'utf-8');
    46. return new Promise(function (resolve, reject) {
    47. reader.onloadend = function (e) {
    48. const data = e.target.result
    49. console.log('data', data)
    50. const wb = XLSX.read(data, {
    51. type: 'buffer'
    52. })
    53. const ws = wb.Sheets[wb.SheetNames[0]]
    54. let arr = XLSX.utils.sheet_to_json(ws);
    55. resolve(arr);
    56. }
    57. });
    58. }
    59. // 封装:把excel转成html或者json。
    60. // 参数:
    61. // file:(excel)文件对象
    62. // outtype:是导出的类型(取值:html,json)
    63. // 调用示例:
    64. // excelTo(文件对象,"html")
    65. // excelTo(文件对象,"json")
    66. export function excelImport(file,outtype="json") {
    67. const types = file.name.split('.')[1]
    68. const fileType = ['xlsx', 'xlc', 'xlm', 'xls', 'xlt'].some(
    69. (item) => item === types
    70. )
    71. if (!fileType) {
    72. this.$message.error('格式错误!请重新选择')
    73. return
    74. }
    75. const reader = new FileReader()
    76. reader.readAsArrayBuffer(file, 'utf-8');
    77. return new Promise(function (resolve, reject) {
    78. reader.onloadend = function (e) {
    79. const data = e.target.result
    80. console.log('data', data)
    81. const wb = XLSX.read(data, {
    82. type: 'buffer'
    83. })
    84. const ws = wb.Sheets[wb.SheetNames[0]];
    85. let result = "";
    86. switch(outtype.toLocaleLowerCase()){
    87. case "html":result = XLSX.utils.sheet_to_html(ws);break;
    88. case "json":result = XLSX.utils.sheet_to_json(ws);break;
    89. default:this.$message.error('输出类型错误,只能取值为 html或者json')
    90. }
    91. resolve(result);
    92. }
    93. });
    94. }

    调用示例:

    1. const importFn=(e)=>{
    2. if(e.target.files && e.target.files.length>0){
    3. httpRequestToHTML(e.target.files[0],"TableContainer")
    4. }
    5. }
    6. <input type="file" onChange={importFn} />
    7. <div id="TableContainer">
    8. </div>

    四、如果想看完整代码的,在下面:

    1、导入导出的工具库:excelUtils.js
    1. // 此工具库是:excel的导入和导出
    2. import * as XLSX from 'xlsx';
    3. // import * as fs from 'file-saver';
    4. import { saveAs } from "file-saver"
    5. // 一、excel的导出:
    6. // 1、根据dom元素导出成excel文件:
    7. // 自动分析dom元素导出excel
    8. // 参数:
    9. // table:表格的dom元素对象
    10. // filename:导出的文件名(不用写扩展名)
    11. export function excelExport(table, filename) {
    12. // workbook,
    13. const wb = XLSX.utils.table_to_book(table);
    14. console.log("wb", wb);
    15. /* Export to file (start a download) */
    16. const defaultCellStyle = {
    17. font: { name: 'Verdana', sz: 13, color: 'FF00FF88' },
    18. fill: { fgColor: { rgb: 'FFFFAA00' } },
    19. }
    20. const wopts = {
    21. bookType: 'xlsx',
    22. bookSST: false,
    23. type: 'binary',
    24. cellStyle: true,
    25. defaultCellStyle: defaultCellStyle,
    26. showGridLines: false,
    27. }
    28. const wbout = XLSX.write(wb, wopts)
    29. const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' })
    30. saveAs(blob, filename + '.xlsx')
    31. }
    32. function s2ab(s) {
    33. console.log("s", s);
    34. var buf = new ArrayBuffer(s.length);
    35. var view = new Uint8Array(buf);
    36. for (var i = 0; i != s.length; ++i) {
    37. view[i] = s.charCodeAt(i) & 0xFF;
    38. }
    39. return buf;
    40. }
    41. // 2、根据json数据(数组)导出成excel文件:
    42. // 参数:
    43. // data:json数组
    44. // headers:excel的表头
    45. // filename:导出的文件名(不用写扩展名)
    46. export function excelExportUseJson(data, headers, filename) {
    47. // 使用深克隆不影响原table数据的展示
    48. const json = cloneDeep(data)
    49. json.forEach(item => {
    50. for (let key in item) {
    51. if (headers.hasOwnProperty(key)) {
    52. item[headers[key]] = item[key]
    53. }
    54. delete item[key]
    55. }
    56. })
    57. // excel 对象
    58. const wb = XLSX.utils.book_new()
    59. // 创建sheet
    60. const ws = XLSX.utils.json_to_sheet(json, { header: Object.values(headers) })
    61. // excel 添加sheet名称
    62. wb.SheetNames.push(filename)
    63. // excel 添加sheet
    64. wb.Sheets[filename] = ws
    65. const defaultCellStyle = {
    66. font: { name: 'Verdana', sz: 13, color: 'FF00FF88' },
    67. fill: { fgColor: { rgb: 'FFFFAA00' } },
    68. }
    69. const wopts = {
    70. bookType: 'xlsx',
    71. bookSST: false,
    72. type: 'binary',
    73. cellStyle: true,
    74. defaultCellStyle: defaultCellStyle,
    75. showGridLines: false,
    76. }
    77. const wbout = XLSX.write(wb, wopts)
    78. const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' })
    79. saveAs(blob, filename + '.xlsx')
    80. }
    81. function cloneDeep(obj) {
    82. if (typeof obj !== 'object' || obj === null) {
    83. return obj;
    84. }
    85. let clonedObj = Array.isArray(obj) ? [] : {};
    86. for (let key in obj) {
    87. if (obj.hasOwnProperty(key)) {
    88. clonedObj[key] = cloneDeep(obj[key]);
    89. }
    90. }
    91. return clonedObj;
    92. }
    93. // 二、从excel文件导入到项目里。
    94. // 1、导入成dom元素:
    95. // 参数:
    96. // data:文件对象(用<input type=file /> 选择到file对象
    97. // domId:导入的excel显示的容器
    98. export function httpRequestToHTML(data, domId) {
    99. const file = data
    100. const types = file.name.split('.')[1]
    101. const fileType = ['xlsx', 'xlc', 'xlm', 'xls', 'xlt'].some(
    102. (item) => item === types
    103. )
    104. if (!fileType) {
    105. this.$message.error('格式错误!请重新选择')
    106. return
    107. }
    108. const reader = new FileReader()
    109. reader.readAsArrayBuffer(file, 'utf-8');
    110. return new Promise(function (resolve, reject) {
    111. reader.onloadend = function (e) {
    112. const data = e.target.result
    113. console.log('data', data)
    114. const wb = XLSX.read(data, {
    115. type: 'buffer'
    116. })
    117. const ws = wb.Sheets[wb.SheetNames[0]]
    118. console.log('ws', ws)
    119. const htmlStr = XLSX.utils.sheet_to_html(ws)
    120. resolve(htmlStr);
    121. }
    122. });
    123. }
    124. // 2、导入成json数据。
    125. // 参数:
    126. // data:文件对象(用<input type=file /> 选择到file对象
    127. export function httpRequestToJSON(data) {
    128. const file = data
    129. const types = file.name.split('.')[1]
    130. const fileType = ['xlsx', 'xlc', 'xlm', 'xls', 'xlt'].some(
    131. (item) => item === types
    132. )
    133. if (!fileType) {
    134. this.$message.error('格式错误!请重新选择')
    135. return
    136. }
    137. const reader = new FileReader()
    138. reader.readAsArrayBuffer(file, 'utf-8');
    139. return new Promise(function (resolve, reject) {
    140. reader.onloadend = function (e) {
    141. const data = e.target.result
    142. console.log('data', data)
    143. const wb = XLSX.read(data, {
    144. type: 'buffer'
    145. })
    146. const ws = wb.Sheets[wb.SheetNames[0]]
    147. let arr = XLSX.utils.sheet_to_json(ws);
    148. resolve(arr);
    149. }
    150. });
    151. }
    152. // 封装:把excel转成html或者json。
    153. // 参数:
    154. // file:(excel)文件对象
    155. // outtype:是导出的类型(取值:html,json)
    156. // 调用示例:
    157. // excelTo(文件对象,"html")
    158. // excelTo(文件对象,"json")
    159. export function excelImport(file,outtype="json") {
    160. const types = file.name.split('.')[1]
    161. const fileType = ['xlsx', 'xlc', 'xlm', 'xls', 'xlt'].some(
    162. (item) => item === types
    163. )
    164. if (!fileType) {
    165. this.$message.error('格式错误!请重新选择')
    166. return
    167. }
    168. const reader = new FileReader()
    169. reader.readAsArrayBuffer(file, 'utf-8');
    170. return new Promise(function (resolve, reject) {
    171. reader.onloadend = function (e) {
    172. const data = e.target.result
    173. console.log('data', data)
    174. const wb = XLSX.read(data, {
    175. type: 'buffer'
    176. })
    177. const ws = wb.Sheets[wb.SheetNames[0]];
    178. let result = "";
    179. switch(outtype.toLocaleLowerCase()){
    180. case "html":result = XLSX.utils.sheet_to_html(ws);break;
    181. case "json":result = XLSX.utils.sheet_to_json(ws);break;
    182. default:this.$message.error('输出类型错误,只能取值为 html或者json')
    183. }
    184. resolve(result);
    185. }
    186. });
    187. }
    2、组件代码:
    1. <template>
    2. <el-button @click="drawer = true" v-if="crud.charAt(0) === '1'">添加轮播图</el-button>
    3. <el-button @click="toExcel01">excel导出(用dom元素)</el-button>
    4. <el-button @click="toExcel02">excel导出(用json数组)</el-button>
    5. <!-- <el-button @click="fromExcel">excel导入</el-button> -->
    6. <!-- <input type="file" @change="fromExcel" /> -->
    7. <el-upload ref="upload" class="upload-demo" :limit="1" :on-change="changeFn" :on-exceed="handleExceed" :auto-upload="false" :show-file-list="false">
    8. <template #trigger>
    9. <el-button type="primary">excel导入</el-button>
    10. </template>
    11. </el-upload>
    12. <el-button @click="batchSave">批量提交</el-button>
    13. <el-button @click="clearAll">清空轮播图数据</el-button>
    14. <el-divider />
    15. <el-table ref="table" id="table01" :data="bannerList" height="600px" style="width: 100%">
    16. <el-table-column prop="bannerid" label="编号" width="180" />
    17. <el-table-column label="图片" width="180">
    18. <template #default="scope">
    19. <img class="img" :src="scope.row.img" />
    20. </template>
    21. </el-table-column>
    22. <el-table-column label="是否启用" v-if="crud.charAt(2) === '1'">
    23. <template #default="scope">
    24. <el-switch v-model="scope.row.flag" />
    25. </template>
    26. </el-table-column>
    27. <el-table-column label="跳转连接">
    28. <template #default="scope">
    29. <el-link :href="scope.row.link" type="primary" target="_blank">跳转连接</el-link>
    30. </template>
    31. </el-table-column>
    32. <el-table-column prop="alt" label="图片提示" />
    33. <el-table-column label="操作" v-if="crud.charAt(2) === '1' || crud.charAt(3) === '1'">
    34. <template #default="scope">
    35. <el-button type="danger" v-if="crud.charAt(3) === '1'" >删除</el-button>
    36. <el-button type="danger" v-if="crud.charAt(2) === '1'">修改</el-button>
    37. </template>
    38. </el-table-column>
    39. </el-table>
    40. <el-drawer v-model="drawer" title="添加轮播图" direction="rtl" :before-close="handleClose">
    41. <AddBannerVue ref="addBannerRef" @ok="okHandle" @cancel="closeDrawer"></AddBannerVue>
    42. </el-drawer>
    43. <hr />
    44. <div id="container"></div>
    45. </template>
    46. <script lang="ts" setup>
    47. import { useRoute } from "vue-router";
    48. import { getBannerApi, addBannerApi,clearBannerApi } from "@/api/banner";
    49. import { onMounted, reactive, ref } from "vue";
    50. import { ElMessageBox } from 'element-plus'
    51. import type { UploadInstance, UploadProps, UploadRawFile,UploadFile } from 'element-plus'
    52. import AddBannerVue from "./AddBanner.vue";
    53. import type { IBanner } from "@/myTypes"
    54. import { excelExport, excelExportUseJson, excelImport } from "@/utils/excelUtils";
    55. const $route = useRoute();//this.$route
    56. const crud: string = $route.meta.crud as string;
    57. const bannerList = reactive<Array<IBanner>>([]);
    58. // 清空轮播图
    59. const clearAll=()=>{
    60. clearBannerApi().then(res=>{
    61. if(res.data.code==="200"){
    62. ElMessageBox.alert("清空成功", "提示", {
    63. confirmButtonText: "确定",
    64. callback: () => {
    65. getBannerList();
    66. }
    67. });
    68. }
    69. }).catch(err=>{
    70. console.log("清空失败",err);
    71. })
    72. }
    73. // 获取轮播图的数据
    74. function getBannerList() {
    75. getBannerApi().then(res => {
    76. if (res.data.code === "200") {
    77. bannerList.length = 0;
    78. bannerList.push(...res.data.data);
    79. }
    80. }).catch(err => {
    81. console.log("获取轮播图失败,err", err);
    82. })
    83. }
    84. // 在初次渲染完毕后,获取轮播图数据
    85. // onMounted(()=>getBannerList());
    86. getBannerList();
    87. // 添加相关:
    88. //
    89. const drawer = ref(false);
    90. function okHandle() {
    91. closeDrawer();
    92. getBannerList();
    93. }
    94. // 关闭抽屉
    95. const closeDrawer = () => {
    96. drawer.value = false;
    97. }
    98. const addBannerRef = ref();
    99. const handleClose = (done: () => void) => {
    100. ElMessageBox.confirm('亲,您真的要关闭吗?')
    101. .then(() => {
    102. console.log("点了确定");
    103. addBannerRef.value.clearData();
    104. done();
    105. })
    106. .catch(() => {
    107. // catch error
    108. console.log("点了取消");
    109. })
    110. }
    111. onMounted(() => console.log("父组件:mounted"))
    112. const toExcel01 = () => {
    113. excelExport(document.getElementById("table01"), "banners");
    114. }
    115. const toExcel02 = () => {
    116. // const arr = bannerList.map(item => ({
    117. // bannerid: item.bannerid,
    118. // img: item.img,
    119. // flag: item.flag ? "是" : "否"
    120. // }))
    121. // excelExportUseJson(arr, {
    122. // bannerid: "编号",
    123. // img: "图片",
    124. // flag: "是否启用"
    125. // }, "bannerList");
    126. excelExportUseJson(bannerList, {
    127. bannerid: "编号",
    128. img: "图片",
    129. flag: "是否启用",
    130. link: "跳转连接",
    131. alt: "图片提示"
    132. }, "bannerList");
    133. }
    134. // 从excel文件中导入
    135. const fromExcel = (e: any) => {
    136. if (e.target.files && e.target.files.length > 0) {
    137. excelImport(e.target.files[0],)
    138. .then((arr: any) => {
    139. bannerList.length = 0;
    140. arr.forEach((item: any) => {
    141. bannerList.push({
    142. bannerid: item["编号"],
    143. img: item["图片"],
    144. flag: item["是否启用"],
    145. link: item["跳转连接"],
    146. alt: item["图片提示"]
    147. });
    148. })
    149. })
    150. }
    151. }
    152. function batchSave() {
    153. let count = 0;
    154. bannerList.forEach((item: any) => {
    155. addBannerApi(item).then(() => {
    156. console.log(`添加成功了${++count}条`);
    157. })
    158. })
    159. }
    160. const upload = ref<UploadInstance>();
    161. const handleExceed: UploadProps['onExceed'] = (files) => {
    162. upload.value!.clearFiles()
    163. const file = files[0] as UploadRawFile
    164. upload.value!.handleStart(file);
    165. }
    166. const changeFn=(file:UploadFile)=>{
    167. console.log("excelImport:file",file);
    168. excelImport(file.raw as File)
    169. .then((arr: any) => {
    170. bannerList.length = 0;
    171. arr.forEach((item: any) => {
    172. bannerList.push({
    173. bannerid: item["编号"],
    174. img: item["图片"],
    175. flag: item["是否启用"],
    176. link: item["跳转连接"],
    177. alt: item["图片提示"]
    178. });
    179. })
    180. })
    181. }
    182. </script>
    183. <style lang="scss" scoped>
    184. .img {
    185. width: 100%;
    186. height: 100px;
    187. }
    188. </style>

  • 相关阅读:
    vue之搭建脚手架快速创建vue项目
    JAVAEE框架技术之14SSM综合案例
    腾讯云部署----DevOps
    网络安全检测与防范 测试题(二)
    FPGA原理与结构(13)——FIFO IP核的使用与测试
    Java on VS Code 8月更新|Spring 功能更新、构建工具改进及调试体验提升
    【js】vue获取document.getElementById(a)为null
    禁止扩展对象
    Android修改开机动画
    Ceph介绍与部署
  • 原文地址:https://blog.csdn.net/jiang7701037/article/details/133283777