Bootstrap

vue el-table 前端js实现导出数据为Excel

目录

一、背景描述

二、功能分析

三、详细开发

1.导出为excel

2.导出为cvs

四、总结


一、背景描述

有些业务常见,例如前端已经获取到表格的所有数据了,并且后端技术人员比较繁忙,总会提出前端分页,前端排序,甚至前端导出数据为excel的需求,所以这个文章就记录一下这个功能怎么实现。实现的功能:导出表格的数据为Excel或cvs,并且前端分页加排序。(不引入第三方库实现导出功能)


二、功能分析

不引入第三方库,所以就前端生成Excel并导出。

前端生成 Excel 文件的方式:首先获取表格数据内容,并对表头进行处理,以确保没有额外的空白单元格。然后,它构建了一个包含表格内容的 HTML 文件,其中包括 Excel 文件所需的一些元信息和样式。接下来,它将该 HTML 文件转换为 Blob 对象,然后通过创建链接并触发下载的方式,实现了文件的下载。

分页排序就比较简单了,只要复制一份表格数据,处理并展示这个数据就行,原始的数据可以用于导出数据。

如下:


三、详细开发

1.导出为excel

首先需要一个表格和导出按钮,如下:

            <el-col :span="4" >
              <el-button type="primary" @click="exportToExcel">导出</el-button>
            </el-col>

            <el-table
              :data="sortedAndPaginatedVerificationTableData"
              stripe
              border
              ref="tableRef"
              @sort-change="handleSortChange"
            >
              <el-table-column prop="age" label="年龄" width="150" sortable>
              </el-table-column>
              <el-table-column prop="status" label="状态" width="120" sortable>
              </el-table-column>
              <el-table-column
                prop="message"
                label="信息"
                sortable
              >
              </el-table-column>
            </el-table>

接着导出功能的实现,2种方式:

第一种,可忽略不看。

//导出Excel
    exportToExcel(){
      //第一种方式
      // 获取表格内容
      const excelContent = this.$refs.tableRef.$el.innerHTML;

      // 处理表头,确保没有额外的空白单元格
      const headerElement = document.createElement('div');
      headerElement.innerHTML = excelContent;
      const headerCells = headerElement.querySelectorAll('th');

      // 移除最后一个空单元格
      if (headerCells.length > 0) {
        const lastCell = headerCells[headerCells.length - 1];
        lastCell.parentNode.removeChild(lastCell);
      }

      // 构建 Excel 文件内容
      let excelFile = `
        <html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:x='urn:schemas-microsoft-com:office:excel' xmlns='http://www.w3.org/TR/REC-html40'>
        <head>
        <!--[if gte mso 9]>
        <xml>
        <x:ExcelWorkbook>
        <x:ExcelWorksheets>
        <x:ExcelWorksheet>
        <x:Name>{worksheet}</x:Name>
        <x:WorksheetOptions>
        <x:DisplayGridlines/>
        </x:WorksheetOptions>
        </x:ExcelWorksheet>
        </x:ExcelWorksheets>
        </x:ExcelWorkbook>
        </xml>
        <![endif]-->
        <style>
        td{border: .5pt solid;}
        </style>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        </head>
        <body>
        ${headerElement.innerHTML}
        </body>
        </html>
      `;

      // 创建 Blob 对象
      const blob = new Blob([excelFile], { type: 'application/vnd.ms-excel' });

      // 创建链接并触发下载
      const link = document.createElement("a");
      link.href = URL.createObjectURL(blob);
      link.download = '表格.xlsx'; // 设置默认文件名
      link.style.display = "none";
      document.body.appendChild(link);
      link.click();
      window.URL.revokeObjectURL(link.href);
      document.body.removeChild(link);

    }

 第二种:

//导出Excel
    exportToExcel(){
      //第二种方式
      
      // 获取表格数据
      const tableData = this.tableData;

      // 构建 Excel 文件内容
      let excelContent = `<html><head><meta charset="UTF-8"></head><body><table border="1">`;

      // 添加表头
      excelContent += '<tr>';
      for (const column of this.$refs.tableRef.columns) {
        if (column.property) {
          excelContent += `<th>${column.label}</th>`;
        }
      }
      excelContent += '</tr>';

      // 添加表格数据
      for (const row of tableData) {
        excelContent += '<tr>';
        for (const column of this.$refs.tableRef.columns) {
          if (column.property) {
            excelContent += `<td>${row[column.property]}</td>`;
          }
        }
        excelContent += '</tr>';
      }

      // 构建完整的 Excel 文件内容
      excelContent += '</table></body></html>';

      // 创建 Blob 对象
      const blob = new Blob([excelContent], { type: 'application/vnd.ms-excel' });

      // 创建链接并触发下载
      const link = document.createElement("a");
      link.href = URL.createObjectURL(blob);
      link.download = '表格.xlsx'; // 设置默认文件名
      link.style.display = "none";
      document.body.appendChild(link);
      link.click();
      window.URL.revokeObjectURL(link.href);
    }

这里tableData是表格的原始数据,如果前端已经获取到表格的所有数据,就可以对整个数据进行导出,也就是推荐第二种方式,第一种方式可以对表格样式进行控制,但是数据是考虑当前页面的表格数据,也就是本页数据的导出,所以后来我摒弃了第一种方式,直接使用的第二种方式。

第二种方式的好处:

  1. 首先,它获取表格数据并遍历每一行,以构建 Excel 文件内容。

  2. 在构建表头时,它遍历了表格的列属性,以获取每一列的标签(label),并添加到表头中,不用控制表格过滤空白单元格,这是第一种的弊端。

2.导出为cvs

     let csvContent = "data:text/csv;charset=utf-8,";
      csvContent += "年龄,状态,信息\n"; // 添加表头

      // 添加数据行
      this.verificationTableData.forEach(row => {
        let csvRow = [];
        csvRow.push(row.age);
        csvRow.push(row.status);
        csvRow.push(row.message);
        csvContent += csvRow.join(",") + "\n";
      });

      // 创建下载链接
      const encodedUri = encodeURI(csvContent);
      const link = document.createElement("a");
      link.setAttribute("href", encodedUri);
      link.setAttribute("download", "data.csv");
      document.body.appendChild(link);

      // 触发点击下载
      link.click();
      document.body.removeChild(link);

 3.前端排序和分页

其实我已经写过不少这个功能,为何还要再提,只是因为我在写上面的功能时,无法沿用之前的写法能实现这个功能,所以记录一下。

sortColumn: '', // 存储当前排序的列
sortOrder: '', // 存储当前排序的顺序




computed: {
    sortedAndPaginatedVerificationTableData() {
      // console.log("sortedAndPaginatedVerificationTableData")
      let data = this.tableData.slice();
      if(data.length<1){
        return []
      }
      // console.log("sortedAndPaginatedVerificationTableData",'com')
      // 根据排序规则进行排序
      if (this.sortColumn && this.sortOrder) {
        data.sort((a, b) => {
          const valueA = a[this.sortColumn];
          const valueB = b[this.sortColumn];
          if (this.sortOrder === 'ascending') {
            if (valueA > valueB) return 1;
            if (valueA < valueB) return -1;
            return 0;
          } else {
            if (valueA > valueB) return -1;
            if (valueA < valueB) return 1;
            return 0;
          }
        });
      }
      // 如果需要分页,则进行分页操作
      if (this.page) {
        const startIndex = (this.page.page - 1) * this.page.limit;
        const endIndex = this.page.page * this.page.limit;
        data = data.slice(startIndex, endIndex);
      }
      return data;
    }
  },




 handleSortChange(column, order) {
      // 更新当前排序的列和顺序
      this.sortColumn = column.prop;
      this.sortOrder = column.order;
      console.log('change',column,order,this.sortColumn,this.sortOrder );
    },

四、总结

使用 HTML 表格和 Blob,将数据动态生成为 HTML 表格,然后通过 HTML5 的 Blob 和 URL.createObjectURL 方法来创建一个链接,最后让用户点击链接下载生成的 Excel 文件。虽然不是真正的 Excel 文件,但可以在大多数情况下满足导出需求。

;