纯前端导出表格数据 -- csv格式 (含表格末尾的自动合计行)

在这里插入图片描述
核心代码详见代码中的注释

<template>
  <div class="page">
    <el-button type="primary" size="small" @click="exportOut">导出</el-button>
    <div class="tableBox">
      <el-table
        :data="tableData"
        border
        :summary-method="getSummaries"
        show-summary
      >
        <el-table-column
          v-for="(item, index) in tableTitleList"
          :key="index"
          :prop="item.prop"
          :label="item.label"
          :width="item.width"
          align="center"
        >
        </el-table-column>
      </el-table>
    </div>
  </div>
</template>

<script>
export default {
      
      
  data() {
      
      
    return {
      
      
      sumRow: {
      
      },
      tableTitleList: [
        {
      
      
          label: "序号",
          prop: "id",
          width: 100,
        },
        {
      
      
          label: "姓名",
          prop: "name",
        },
        {
      
      
          label: "射击次数",
          prop: "total",
        },
        {
      
      
          label: "命中次数",
          prop: "hitNum",
        },
        {
      
      
          label: "命中率",
          prop: "hitRate",
        },
      ],
      tableData: [
        {
      
      
          id: "1",
          name: "张三",
          total: 100,
          hitNum: 10,
          hitRate: "10%",
        },
        {
      
      
          id: "2",
          name: "王五",
          total: 100,
          hitNum: 20,
          hitRate: "20%",
        },
      ],
    };
  },
  methods: {
      
      
    // 导出为 csv 格式的文件
    exportOut() {
      
      
      // 生成时间戳,避免每次导出的文件重名
      let timeStamp = new Date().getTime();
      // 在数据末尾添加合计行
      let data = [...this.tableData, this.sumRow];
      downloadCsv(this.tableTitleList, data, `导出的数据_${ 
        timeStamp}.csv`);
    },
    // 自定义末尾的合计逻辑
    getSummaries(param) {
      
      
      const {
      
       columns, data } = param;
      const sumDic = {
      
      };
      columns.forEach((column, index) => {
      
      
        // 第 1 列
        if (index === 0) {
      
      
          sumDic[column.property] = "合计";
          return;
        }

        // 需特殊计算的列
        if (column.property === "hitRate") {
      
      
          sumDic[column.property] =
            ((sumDic["hitNum"] / sumDic["total"]) * 100).toFixed(2) + "%";
          return;
        }

        // 其他列默认求和
        const values = data.map((item) => Number(item[column.property]));
        if (!values.every((value) => isNaN(value))) {
      
      
          // 可以求和的列
          sumDic[column.property] = values.reduce((prev, curr) => {
      
      
            const value = Number(curr);
            if (!isNaN(value)) {
      
      
              return prev + curr;
            } else {
      
      
              return prev;
            }
          }, 0);
        } else {
      
      
          // 无法求和的列
          sumDic[column.property] = "——";
        }
      });

      // 指定列添加单位
      sumDic["total"] += " 次";
      sumDic["hitNum"] += " 次";
      // 获取末尾的合计行
      this.sumRow = sumDic;
      return Object.values(sumDic);
    },
  },
};

// 纯js导出 csv 格式文件
function downloadCsv(header, data, fileName = "导出结果.csv") {
      
      
  if (
    !header ||
    !data ||
    !Array.isArray(header) ||
    !Array.isArray(data) ||
    !header.length ||
    !data.length
  ) {
      
      
    return;
  }
  var csvContent = "data:text/csv;charset=utf-8,\ufeff";
  const _header = header.map((h) => h.label).join(",");
  const keys = header.map((item) => item.prop);
  csvContent += _header + "\n";
  data.forEach((item, index) => {
      
      
    let dataString = "";
    for (let i = 0; i < keys.length; i++) {
      
      
      dataString += item[keys[i]] + ",";
    }
    csvContent +=
      index < data.length
        ? dataString.replace(/,$/, "\n")
        : dataString.replace(/,$/, "");
  });
  const a = document.createElement("a");
  a.href = encodeURI(csvContent);
  a.download = fileName;
  a.click();
  window.URL.revokeObjectURL(csvContent);
}
</script>

<style scoped>
.page {
      
      
  padding: 30px;
}
.tableBox {
      
      
  margin: 20px 0px;
}
</style> 

猜你喜欢

转载自blog.csdn.net/weixin_41192489/article/details/129861367