vue项目:使用xlsx导出Excel数据

文章目录


一、安装xlsx

执行命令:npm i xlsx file-saver --save

二、报错及解决

使用时:import XLSX from "xlsx"; 发现如下报错信息

报错原因:xlsx版本不兼容。

解决也很简单:

1)先移除已安装的xlsx: npm uninstall xlsx

2)安装低版本:npm i xlsx@0.17.0

三、编写公共方法

javascript 复制代码
// exportExcel.js
import { saveAs } from "file-saver";
import XLSX from "xlsx";

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

function sheet_from_array_of_arrays(data) {
  let ws = {};
  let range = {
    s: {
      c: 10000000,
      r: 10000000
    },
    e: {
      c: 0,
      r: 0
    }
  };
  for (let R = 0; R != data.length; ++R) {
    for (let 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;
      let cell = {
        v: data[R][C]
      };
      if (cell.v == null) continue;
      const 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 s2ab(s) {
  let buf = new ArrayBuffer(s.length);
  let view = new Uint8Array(buf);
  for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
  return buf;
}

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

/**
 * @description 导出表格数据
 * @param {Array} header 表头
 * @param {Array} data 数据
 * @param {String} filename 文件名
 * @param {merges} header 表头
 * @param {autoWidth} header 是否自适应表格内容宽度
 * @param {bookType} header excel文件后缀名
 */
export function exportJson2Excel({
  header = [],
  data = [],
  filename = "excel",
  merges = [],
  autoWidth = true,
  bookType = "xlsx"
} = {}) {
  let dataKeys = [];
  // 处理xlsx头部
  header = header.map(item => {
    dataKeys.push(item.key);
    return item.value;
  });
  // 处理data数据
  data = data.map(item => {
    const dataOne = dataKeys.map(key => item[key]);
    return [...dataOne];
  });
  header.length > 0 && data.unshift(header);
  let 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;
  }
  const ws_name = "SheetJS";
  const wb = new Workbook();
  // 将工作表添加到工作簿
  wb.SheetNames.push(ws_name);
  wb.Sheets[ws_name] = ws;
  const wbout = XLSX.write(wb, {
    bookType: bookType,
    bookSST: false,
    type: "binary"
  });
  saveAs(
    new Blob([s2ab(wbout)], {
      type: "application/octet-stream"
    }),
    `${filename}.${bookType}`
  );
}

四、方法使用

javascript 复制代码
<template>
  <div class="hello">
    <el-button type="primary" @click="handleExport">导出为Excel</el-button>
    <el-table :data="tableData" border>
      <el-table-column
        v-for="item in header"
        :key="item.key"
        :label="item.value"
        :prop="item.key"
      >
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
import { exportJson2Excel } from "../utils/exportExcel.js";

export default {
  data() {
    return {
      message: "",
      header: [
        {
          key: "id",
          value: "ID"
        },
        {
          key: "title",
          value: "名称"
        },
        {
          key: "tag",
          value: "标签"
        },
        {
          key: "typeText",
          value: "方式"
        },
        {
          key: "cycle",
          value: "周期"
        },
        {
          key: "status",
          value: "状态"
        }
      ],
      tableData: [
        {
          id: 44,
          title: "test111122222",
          tag: "",
          typeText: "定时任务",
          cycle: "每天 9:00",
          status: "草稿"
        },
        {
          id: 45,
          title:
            "名称很长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长",
          tag: "hhh",
          typeText: "定时任务",
          cycle: "每天 12:00",
          status: "草稿"
        },
        {
          id: 45,
          title: "测试测试测试",
          tag: "hhh",
          typeText: "定时任务",
          cycle: "每天 00:00",
          status: "草稿"
        },
        {
          id: 47,
          title: "嗯嗯嗯",
          tag: "hhh",
          typeText: "定时任务",
          cycle: "每天 10:00",
          status: "草稿"
        },
        {
          id: 48,
          title: "test",
          tag: "null",
          typeText: "循环任务",
          cycle: "每天 19:00",
          status: "正式"
        }
      ]
    };
  },
  methods: {
    handleExport() {
      console.log("export");
      exportJson2Excel({
        data: this.tableData,
        header: this.header
      });
    }
};
</script>

页面页面展示,及导出结果:

相关推荐
糕冷小美n5 小时前
elementuivue2表格不覆盖整个表格添加固定属性
前端·javascript·elementui
小哥不太逍遥6 小时前
Technical Report 2024
java·服务器·前端
沐墨染6 小时前
黑词分析与可疑对话挖掘组件的设计与实现
前端·elementui·数据挖掘·数据分析·vue·visual studio code
anOnion6 小时前
构建无障碍组件之Disclosure Pattern
前端·html·交互设计
threerocks6 小时前
前端将死,Agent 永生
前端·人工智能·ai编程
问道飞鱼7 小时前
【前端知识】Vite用法从入门到实战
前端·vite·项目构建
爱上妖精的尾巴7 小时前
8-10 WPS JSA 正则表达式:贪婪匹配
服务器·前端·javascript·正则表达式·wps·jsa
Zhencode7 小时前
Vue3响应式原理之ref篇
vue.js
小疙瘩8 小时前
element-ui 中 el-upload 多文件一次性上传的实现
javascript·vue.js·ui
Aliex_git8 小时前
浏览器 API 兼容性解决方案
前端·笔记·学习