VUE 前端操作Excel下载数据

1.引入组件库

npm install xlsx file-saver -S //导出数据的包

npm install script-loader -S -D

2.utils创建js包

Export2Excel.js

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

// file-saver:控制下载
// xlsx:excel 的编辑器和解析器

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'
  )
}

// 我希望这个 param 用户没有传递的时候,它是一个对象
// export function export_json_to_excel(param = {}) {}

// 这个空对象里面有一个叫做 multiHeader 的属性,并且希望这个 multiHeader 默认是一个数组
// export function export_json_to_excel({ multiHeader = [] } = {}) {}

// 还能有 header、data、filename 等等参数,这些参数不需要有默认值
// export function export_json_to_excel({
//   multiHeader = [],
//   header,
//   data,
//   filename
// } = {}) {}

/**
 * 接收一个对象,执行 excel 的下载功能
 * @param {*} param0 这个方法接收一个对象,这个对象应该包含这些参数,如果不包含,那么会存在默认的这些参数
 * @param {*} param.header 数组,数组中每一个元素表示当前表头的第几列
 * @param {*} param.data 二维数组,每个数组表示当前第几行,每个数组中的每个元素表示当前行的当前列
 * @param {*} param.multiHeader 二维数组 每个数组表示当前一层表头,多个数组就表示多层
 * @param {*} param.merges 数组 合并行列
 */
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))
    })
  }

  if (autoWidth) {
    /*设置worksheet每列的最大宽度*/
    const colWidth = data.map((row) =>
      row.map((val) => {
        /*先判断是否为null/undefined*/
        if (val == null) {
          return {
            wch: 10
          }
        } else if (val.toString().charCodeAt(0) > 255) {
          /*再判断是否为中文*/
          return {
            wch: val.toString().length * 2
          }
        } else {
          return {
            wch: val.toString().length
          }
        }
      })
    )
    /*以第一行为初始值*/
    let result = colWidth[0]
    for (let i = 1; i < colWidth.length; i++) {
      for (let j = 0; j < colWidth[i].length; j++) {
        if (result[j]['wch'] < colWidth[i][j]['wch']) {
          result[j]['wch'] = colWidth[i][j]['wch']
        }
      }
    }
    ws['!cols'] = result
  }

  /* 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}`
  )
}

3.vue 页面

<p @click="excelDownload">excel下载</p>

js方法

    // excel下载
    async excelDownload() {
      // 获取列表数据
      const {
        data: { rows },
      } = await getListData({
        ...this.search,
        ...this.listQuery,
        ...{
          pager: {
            pageSize: this.totalRows,
          },
        },
      });
      console.log(rows);
      // excel 表头
      const chineEnglish = {
        userName: "用户账号",
        goodsName: "饰品名称",
        historyPrice: "当时价格(R)",
        zbtMinPrice: "扎比特最低价(R)",
        uuMinPrice: "UU最低价(R)",
        v5MinPrice: "V5最低价(R)",
        nowPrice: "此时价格(R)",
        tradePrice: "交易价格(R)",
        drawStatusName: "提取状态",
        tradeStatusName: "交易状态",
        drawType: "发货来源",
        orderId: "订单号",
        goodsOriginName: "饰品来源",
        boxName: "箱子名称",
        errorDes: "交易报错",
        drawTime: "发起时间",
        crtTime: "下单时间",
        recipeTime: "接受时间",
        steamId: "第三方_ID",
        wear: "饰品磨损",
      };
      const resules = [];
      rows.forEach((item) => {
        const arrPush = [];
        Object.keys(chineEnglish).forEach((key) => {
          let keyPlll = item[key];
          // 枚举值替换
          if (key === "drawType") {
            keyPlll = this.drawTypeFilter(item[key]);
          }
          arrPush.push(keyPlll);
        });
        resules.push(arrPush);
      });
      console.log(resules);
      import("@/utils/excel/Export2Excel.js").then((excel) => {
        excel.export_json_to_excel({
          header: Object.values(chineEnglish), // 中英文对照表, 这里是数组
          filename: "下载",
          // this.shuju
          data: resules, // 导出的数据,是数组包数组[[], []]
          bookType: "xlsx", // 导出的类型可以为, xlsx , csv, text, more
        });
      });
      // sd
    },
相关推荐
神之王楠9 分钟前
如何通过js加载css和html
javascript·css·html
余生H13 分钟前
前端的全栈混合之路Meteor篇:关于前后端分离及与各框架的对比
前端·javascript·node.js·全栈
花花鱼14 分钟前
@antv/x6 导出图片下载,或者导出图片为base64由后端去处理。
vue.js
程序员-珍16 分钟前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发
axihaihai21 分钟前
网站开发的发展(后端路由/前后端分离/前端路由)
前端
流烟默33 分钟前
Vue中watch监听属性的一些应用总结
前端·javascript·vue.js·watch
2401_8572979143 分钟前
招联金融2025校招内推
java·前端·算法·金融·求职招聘
茶卡盐佑星_1 小时前
meta标签作用/SEO优化
前端·javascript·html
与衫1 小时前
掌握嵌套子查询:复杂 SQL 中 * 列的准确表列关系
android·javascript·sql
Ink1 小时前
从底层看 path.resolve 实现
前端·node.js