前端自定义导出功能(轮子)不需要调用后端接口

  1. 需求背景

我们项目总会遇到这种导出表格数据功能,如勾选到表格哪一个,点击导出,导出excel数据时只导出勾选中的数据,不勾选时则导出全部数据,我们按照正常的逻辑来说,是需要调后端的接口,如当需要调勾选数据时,我们可能向后端传个参数如ids=['11','22'],导出全部则传空之类的。但通过我这个封装的工具类,表格上有的数据前端都可以自己导出来,接下来让我们进入正题

  1. 需求工具类封装实现

  1. vue项目中,使用file-saver导出文件,下载Excel文件、下载图片、下载文本,关于file-saver小伙伴感兴趣的可以自行搜索功能,以及我们使用到vue中XLSX导出表格xlsx文件插件,我们项目先自行安装npm一下

npm install file-saver --save
npm install --save xlsx
  1. 代码如下

import * as XLSX from "xlsx";
import { saveAs } from 'file-saver'

/**
 * @Copyright  导出工具类
 * @Description: 将接口返回的数组数据导出为Excel
 * @param list
 * @param columns_list
 * @param tabData 接口返回的列表数据 Array
 * @param sheetName 待导出的excel中sheet名称 String or Array
 * @param tableName 待导出的excel名称 String
 * @author Chensina
 * @date 2023年03月22日
 * @update  [序号][日期YYYY-MM-DD][更改人姓名][变更描述]
 */
export function exportAuto(list, columns_list, sheetName, tableName) {
  var reData = [];
  list.map((item, index) => {
    var reObj = {};
    columns_list
      // .filter((item) => item.isShowCol)
      .forEach((value, key) => {
        if (value.label != undefined) {
          for (let i = 0; i < Object.keys(item).length; i++) {
            if (value.prop == Object.keys(item)[i]) {
              if (value.prop == "num") {
                reObj[value.label] = index + 1;
              } else {
                reObj[value.label] = Object.values(item)[i];
              }
            }
          }
        }
      });
    reData.push(reObj);
  });
  exportExcel(reData, sheetName, tableName);
}

/**
 * @Copyright  导出工具类
 * @Description: 将接口返回的数组数据导出为Excel
 * @param tabData 接口返回的列表数据 Array
 * @param sheetName 待导出的excel中sheet名称 String or Array
 * @param tableName 待导出的excel名称 String
 * @author Chensina
 * @date 2023年03月22日
 * @update  [序号][日期YYYY-MM-DD][更改人姓名][变更描述]
 */
export function exportExcel(tabData, sheetName, tableName) {
  let isArrayData = Array.isArray(tabData),
    isArraySheet = Array.isArray(sheetName);
  /* create a new blank workbook */
  let wb = XLSX.utils.book_new();
  if (isArrayData && isArraySheet) {
    tabData.forEach((item, index) => {
      XLSX.utils.book_append_sheet(
        wb,
        XLSX.utils.json_to_sheet(item),
        sheetName[index]
      );
    });
  } else {
    let sheet = XLSX.utils.json_to_sheet(tabData);
    let colWidths = [];
    let colNames = Object.keys(tabData[0]); // 所有列的名称数组
    // 计算每一列的所有单元格宽度
    // 先遍历行
    tabData.forEach((row) => {
      // 列序号
      let index = 0;
      // 遍历列
      for (const key in row) {
        if (colWidths[index] == null) colWidths[index] = [];
        switch (typeof row[key]) {
          case "string":
          case "number":
          case "boolean":
            colWidths[index].push(getCellWidth(row[key]));
            break;
          case "object":
          case "function":
            colWidths[index].push(0);
            break;
        }
        index++;
      }
    });
    let wi = [];
    colWidths.forEach((widths, index) => {
      // 计算列头的宽度
      widths.push(getCellWidth(colNames[index]));
      // 设置最大值为列宽
      //wi.push({ wpx: Math.max(...widths) * 5.5 })
      wi.push({ wch: Math.max(...widths) });
    });
    sheet["!cols"] = wi;
    XLSX.utils.book_append_sheet(wb, sheet, sheetName);
  }
  let wbout = XLSX.write(wb, {
    bookType: "xlsx",
    bookSST: true,
    type: "array",
  });
  try {
    //保存文件
    saveAs(
      new Blob([wbout], {
        type: "application/octet-stream;charset=utf-8",
      }),
      //`${tableName}_${new Date().Format('yyyy-MM-dd hh:mm:ss')}.xlsx`
      `${tableName}.xlsx`
    );
  } catch (e) {
    if (typeof console !== "undefined") console.log(e, wbout);
  }
}

function getCellWidth(value) {
  // 判断是否为null或undefined
  if (value == null) {
    return 10;
  } else if (/.*[\u4e00-\u9fa5]+.*$/.test(value)) {
    // 判断是否包含中文
    return value.toString().length * 2.1;
  } else {
    return value.toString().length * 1.1;
    /* 另一种方案
      value = value.toString()
      return value.replace(/[\u0391-\uFFE5]/g, 'aa').length
      */
  }
}
  1. 需求实践

  1. 页面引用

<template>
    <div>
        <el-button type="primary" @click="exportExcel">导出</el-button>
    </div>
</template>
 //自己根据自己需求定义要导出的字段,如有一些状态是Y,N的,要导出中文可以自己先处理
exportcolumns: [
        { label: '序号', type: 'index' },
        {
          label: '销售件编码',
          prop: 'setPrdCode',
          width: '180',
          sortable: true,
        },
        {
          label: '销售件名称',
          prop: 'setProductName',
          width: '180',
          sortable: true,
        },
        {
          label: '销售件名称2',
          prop: 'setProductName2',
          width: '180',
          sortable: true,
        },
        {
          label: '销售件状态',
          prop: 'setProductStatusName',
          width: '180',
        },
        {
          label: '营销组织',
          prop: 'salesOrgName',
          width: '180',
        },
        {
          label: '产品线',
          prop: 'productLineName',
          width: '180',
        },

      ],
import { exportAuto } from "@/utils/export.js";

// 导出
exportExcel() {
  this.currentTime = this.getCurrentTime(); //获取当前时间
  //当页面上选择数据时导出选中数据
  //this.multipleSelection表格当前勾选中的数据
  //exportcolumns你需要导出的字段
  if (this.multipleSelection && this.multipleSelection.length > 0) {
    //导出勾选数据
    exportAuto(
      this.multipleSelection, //勾选中的数据
      this.exportcolumns, //要导出的字段
      "制造码与销售码列表", //excel中sheet名称
      "销售码与制造码查询结果-" + this.currentTime //导出的excel名称
    );
  } else {
    //导出全部
    if (!!this.list) {
      exportAuto(
        this.list,
        this.exportcolumns,
        "制造码与销售码列表",
        "销售码与制造码查询结果-" + this.currentTime
      );
    }
  }
},
  1. 需求效果截图

  1. 当有勾选数据时

2.当无勾选数据直接点击导出时

好的小伙伴们就在这里演示完毕,有问题的欢迎随时咨询

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值