Vue exports Excel tables and implements the method of merging cells

 Installation dependencies:

"file-saver" is a JavaScript library for saving files in the browser. It provides an easy way to allow you to create and download files client-side via JavaScript without server involvement. With file-saver, you can save generated data (such as data obtained from the backend or processed data) as a file, which users can download and save to their local computers.

cnpm install file-saver --save

 "xlsx" is the file format used for Microsoft Excel files. It stands for "XML Spreadsheet" and is commonly used for storing and manipulating spreadsheet data. In web development, you can use various JavaScript libraries to handle xlsx files, providing functions for reading, writing and manipulating Excel files.

cnpm install xlsx --save

"script-loader" is a tool for dynamically loading JavaScript scripts. It provides a way to load external JavaScript files at runtime without explicitly adding <script> tags to the HTML. This is useful for loading specific JavaScript files on demand or loading different script files based on conditions. Using script-loader, you can asynchronously load and execute JavaScript code when needed to optimize page load performance and resource utilization.

cnpm install script-loader --save-dev

 Download the Export2Excel.js file and create the directory vassets/Export2Excel.js under src

The following is the downloaded Export2Excel.js file:

/* eslint-disable */
import { saveAs } from 'file-saver'
import * as XLSX from 'xlsx'

function generateArray(table) {
  var out = [];
  var rows = table.querySelectorAll('tr');
  var ranges = [];
  for (var R = 0; R < rows.length; ++R) {
    var outRow = [];
    var row = rows[R];
    var columns = row.querySelectorAll('td');
    for (var C = 0; C < columns.length; ++C) {
      var cell = columns[C];
      var colspan = cell.getAttribute('colspan');
      var rowspan = cell.getAttribute('rowspan');
      var cellValue = cell.innerText;
      if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue;

      //Skip ranges
      ranges.forEach(function (range) {
        if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) {
          for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null);
        }
      });

      //Handle Row Span
      if (rowspan || colspan) {
        rowspan = rowspan || 1;
        colspan = colspan || 1;
        ranges.push({
          s: {
            r: R,
            c: outRow.length
          },
          e: {
            r: R + rowspan - 1,
            c: outRow.length + colspan - 1
          }
        });
      };

      //Handle Value
      outRow.push(cellValue !== "" ? cellValue : null);

      //Handle Colspan
      if (colspan)
        for (var k = 0; k < colspan - 1; ++k) outRow.push(null);
    }
    out.push(outRow);
  }
  return [out, ranges];
};

function datenum(v, date1904) {
  if (date1904) v += 1462;
  var epoch = Date.parse(v);
  return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
}

function sheet_from_array_of_arrays(data, opts) {
  var ws = {};
  var range = {
    s: {
      c: 10000000,
      r: 10000000
    },
    e: {
      c: 0,
      r: 0
    }
  };
  for (var R = 0; R != data.length; ++R) {
    for (var C = 0; C != data[R].length; ++C) {
      if (range.s.r > R) range.s.r = R;
      if (range.s.c > C) range.s.c = C;
      if (range.e.r < R) range.e.r = R;
      if (range.e.c < C) range.e.c = C;
      var cell = {
        v: data[R][C]
      };
      if (cell.v == null) continue;
      var cell_ref = XLSX.utils.encode_cell({
        c: C,
        r: R
      });

      if (typeof cell.v === 'number') cell.t = 'n';
      else if (typeof cell.v === 'boolean') cell.t = 'b';
      else if (cell.v instanceof Date) {
        cell.t = 'n';
        cell.z = XLSX.SSF._table[14];
        cell.v = datenum(cell.v);
      } else cell.t = 's';

      ws[cell_ref] = cell;
    }
  }
  if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);
  return ws;
}

function Workbook() {
  if (!(this instanceof Workbook)) return new Workbook();
  this.SheetNames = [];
  this.Sheets = {};
}

function s2ab(s) {
  var buf = new ArrayBuffer(s.length);
  var view = new Uint8Array(buf);
  for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
  return buf;
}

export function export_table_to_excel(id) {
  var theTable = document.getElementById(id);
  var oo = generateArray(theTable);
  var ranges = oo[1];

  /* original data */
  var data = oo[0];
  var ws_name = "SheetJS";

  var wb = new Workbook(),
    ws = sheet_from_array_of_arrays(data);

  /* add ranges to worksheet */
  // ws['!cols'] = ['apple', 'banan'];
  ws['!merges'] = ranges;

  /* add worksheet to workbook */
  wb.SheetNames.push(ws_name);
  wb.Sheets[ws_name] = ws;

  var wbout = XLSX.write(wb, {
    bookType: 'xlsx',
    bookSST: false,
    type: 'binary'
  });

  saveAs(new Blob([s2ab(wbout)], {
    type: "application/octet-stream"
  }), "test.xlsx")
}

export function export_json_to_excel({
  multiHeader = [],
  header,
  data,
  filename,
  merges = [],
  autoWidth = true,
  bookType = 'xlsx'
} = {}) {
  /* original data */
  filename = filename || 'excel-list'
  data = [...data]
  data.unshift(header);
  for (let i = multiHeader.length - 1; i > -1; i--) {
    data.unshift(multiHeader[i])
  }

  var ws_name = "SheetJS";
  var wb = new Workbook(),
    ws = sheet_from_array_of_arrays(data);

  if (merges.length > 0) {
    if (!ws['!merges']) ws['!merges'] = [];
    merges.forEach(item => {
      ws['!merges'].push(XLSX.utils.decode_range(item))
    })
  }


  /* add worksheet to workbook */
  wb.SheetNames.push(ws_name);
  wb.Sheets[ws_name] = ws;

  var wbout = XLSX.write(wb, {
    bookType: bookType,
    bookSST: false,
    type: 'binary'
  });
  saveAs(new Blob([s2ab(wbout)], {
    type: "application/octet-stream"
  }), `${filename}.${bookType}`);
}

used in the component 

//导出方法
exportExcel () {
  import('@/assets/Export2Excel').then(excel => {
    const multiHeader = [['标题', '','']] // 标题
    const header = ['姓名', '年龄','手机号'] // 表头
    const filterVal = ['username', 'age','mobile'] // 数据属性
    const list = this.tableData //请求来的数据
    const merges = ['A1:B1'] //需要合并的单元格
    const data = list.map(item => filterVal.map(j => item[j])) // 转换二维数组
    const filename = '复杂员工列表'
    excel.export_json_to_excel({
      multiHeader, // 标题--非必要
      header, // 表头
      data,  // 具体数据--二维数组
      merges, // 合并--非必要
      filename // 下载文件名
    })
  })
}

tableData data structure:

tableData: [{
  correctionTime: '2018-11-30',
  mobile: '13800000001',
  timeOfEntry: '2025-11-01',
  username: '张三',
  age: '21'
},
{
  correctionTime: '2018-11-30',
  mobile: '13800000002',
  timeOfEntry: '2025-11-01',
  username: '李四',
  age: '23'
}]

Guess you like

Origin blog.csdn.net/weixin_44523517/article/details/126148715
Recommended