1 安装之后报错
npm install xlsx --save
npm install xlsx-style --save 
Umi运行会报错

自己代码
import XLSX from "xlsx";
import XLSXStyle from "xlsx-style";
const data = [
  [
    "demo1",
    "demo2",
    "demo3",
    "demo4",
    "demo5",
    "是否开启(填写注意: 0为否,1为是)",
  ],
  ["1", "2", "3", "4", "5", "0"],
];
const wsWidths = [20, 20, 20, 20, 20, 20];
const book = XLSX.utils.book_new(); //没有工作表的空工作簿
const workSheet = XLSX.utils.aoa_to_sheet(data);
if (Array.isArray(wsWidths) && wsWidths.length === columnNames[0].length) {
  workSheet["!cols"] = wsWidths.map((width) => ({ wch: width }));
}
if (merge) {
  /**
     *
      合并单元格:
      // s 意为 start ,即开始的单元格
      // r 是 row ,表示行号,从 0 计起
      // c 是 col ,表示列号,从 0 计起
      const merge = [
        // 纵向合并,范围是第1列的行1到行2
        { s: { r: 0, c: 0 }, e: { r: 1, c: 0 } },
        // 纵向合并,范围是第2列的行1到行2
        { s: { r: 0, c: 1 }, e: { r: 1, c: 1 } },
        // 横向合并,范围是第1行的列3到列5
        { s: { r: 0, c: 2 }, e: { r: 0, c: 4 } },
        // 横向合并,范围是第1行的列6到列11
        { s: { r: 0, c: 5 }, e: { r: 0, c: 10 } },
        // 横向合并,范围是第1行的列12到列17
        { s: { r: 0, c: 11 }, e: { r: 0, c: 16 } },
        // 横向合并,范围是第1行的列18到列23
        { s: { r: 0, c: 17 }, e: { r: 0, c: 22 } },
        // 横向合并,范围是第1行的列24到列29
        { s: { r: 0, c: 23 }, e: { r: 0, c: 28 } },
        // 横向合并,范围是第1行的列30到列35
        { s: { r: 0, c: 29 }, e: { r: 0, c: 34 } }
      ];
    */
  workSheet["!merges"] = merge;
}
const colKeys = Object.keys(workSheet).filter((k) => /[A-Z]/.test(k[0]));
styles.forEach((s, i) => {
  const t = columnNames[0][i];
  const j = colKeys.findIndex((k) => workSheet[k].v === t);
  if (s && j > -1) {
    workSheet[colKeys[j]].s = s;
  }
});
XLSX.utils.book_append_sheet(book, workSheet, sheetName);
XLSXStyle.writeFile(book, filename, {
  defaultCellStyle /* {
      font: { name: "Verdana", sz: 14, color: {rgb: "FFFF0000"}},
      fill: {fgColor: {rgb: "FF00FF00"}},
      alignment: {vertical: 'center'}
    } */,
});
 
 
 
解决方案1:配置webpack
externals: {
     './cptable': 'var cptable',
}, 
Umi在config.ts中配置。
解决方案2:删除两个导入 (最佳方案)
import XLSX from "xlsx";
import XLSXStyle from "xlsx-style"; 
 
删除之后,上面的代码就能正常使用,编译也不报错了,也不需要进行webpack配置。
因为这两个库不支持ES 6的导出,导出的值是undefined。
解决方案3
使用方案1生成表格时候报错:
![]()
意思就是
XLSX为undefined,我去这不是import导入进来了吗,怎么就undefined了。
直接进入XLSX源码查看。

源码里面根本就没有导出XLSX。直接挂在window上面的,什么玩意啊。
修改自己的代码
const data = [
  [
    "demo1",
    "demo2",
    "demo3",
    "demo4",
    "demo5",
    "是否开启(填写注意: 0为否,1为是)",
  ],
  ["1", "2", "3", "4", "5", "0"],
];
const wsWidths = [20, 20, 20, 20, 20, 20];
const book = window.XLSX.utils.book_new(); //没有工作表的空工作簿
const workSheet = window.XLSX.utils.aoa_to_sheet(data);
if (Array.isArray(wsWidths) && wsWidths.length === columnNames[0].length) {
  workSheet["!cols"] = wsWidths.map((width) => ({ wch: width }));
}
if (merge) {
  /**
     *
      合并单元格:
      // s 意为 start ,即开始的单元格
      // r 是 row ,表示行号,从 0 计起
      // c 是 col ,表示列号,从 0 计起
      const merge = [
        // 纵向合并,范围是第1列的行1到行2
        { s: { r: 0, c: 0 }, e: { r: 1, c: 0 } },
        // 纵向合并,范围是第2列的行1到行2
        { s: { r: 0, c: 1 }, e: { r: 1, c: 1 } },
        // 横向合并,范围是第1行的列3到列5
        { s: { r: 0, c: 2 }, e: { r: 0, c: 4 } },
        // 横向合并,范围是第1行的列6到列11
        { s: { r: 0, c: 5 }, e: { r: 0, c: 10 } },
        // 横向合并,范围是第1行的列12到列17
        { s: { r: 0, c: 11 }, e: { r: 0, c: 16 } },
        // 横向合并,范围是第1行的列18到列23
        { s: { r: 0, c: 17 }, e: { r: 0, c: 22 } },
        // 横向合并,范围是第1行的列24到列29
        { s: { r: 0, c: 23 }, e: { r: 0, c: 28 } },
        // 横向合并,范围是第1行的列30到列35
        { s: { r: 0, c: 29 }, e: { r: 0, c: 34 } }
      ];
    */
  workSheet["!merges"] = merge;
}
const colKeys = Object.keys(workSheet).filter((k) => /[A-Z]/.test(k[0]));
styles.forEach((s, i) => {
  const t = columnNames[0][i];
  const j = colKeys.findIndex((k) => workSheet[k].v === t);
  if (s && j > -1) {
    workSheet[colKeys[j]].s = s;
  }
});
 window.XLSX.utils.book_append_sheet(book, workSheet, sheetName);
 window.XLSXStyle.writeFile(book, filename, {
   defaultCellStyle /* {
      font: { name: "Verdana", sz: 14, color: {rgb: "FFFF0000"}},
      fill: {fgColor: {rgb: "FF00FF00"}},
      alignment: {vertical: 'center'}
    } */,
 });
 
直接使用window点对应的方法。
生成文件内容

2 文件解析
import { Upload } from "antd";
<Upload
  accept=".xlsx"
  fileList={[]}
  beforeUpload={(file) => onBeforeUpload(file)}
>
  <Button>批量上传</Button>
</Upload>; 
 
const isBinary =
  typeof FileReader !== "undefined" &&
  typeof FileReader.prototype !== "undefined" &&
  typeof FileReader.prototype.readAsBinaryString !== "undefined";
let myParseWorker;
function formatData(data) {
  var o = "",
    l = 0,
    w = 10240;
  for (; l < data.byteLength / w; ++l)
    o += String.fromCharCode.apply(
      null,
      new Uint8Array(data.slice(l * w, l * w + w))
    );
  o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)));
  return o;
}
function parseWorker(data) {
  if (!myParseWorker) {
    myParseWorker = new Worker(
      `${
        window.location.protocol +
        "//" +
        window.location.host +
        window.location.pathname
      }xlsx.worker.js`
    );
  }
  return new Promise((resolve, reject) => {
    myParseWorker.onmessage = function (e) {
      switch (e.data.type) {
        case "error":
          reject(e.data.data);
          break;
        case "xlsx":
          return resolve(JSON.parse(e.data.data));
      }
    };
    data = isBinary ? data : btoa(formatData(data));
    myParseWorker.postMessage({ data, binary: isBinary });
  });
}
const onBeforeUpload = async (file) => {
  try {
    const res = new Promise((resolve, reject) => {
      const myFileReader = new FileReader();
      myFileReader.onload = (e) => {
        try {
          parseWorker(e.target.result)
            .then((res) => {
              //if里面可以增加自己的校验方法
              if (true) {
                return resolve(file);
              }
              return reject(e);
            })
            .catch((error) => {
              console.log(error);
              reject(error);
            });
        } catch (error) {
          console.log(error);
          reject(error);
        }
      };
      if (isBinary) {
        myFileReader.readAsBinaryString(file);
      } else {
        myFileReader.readAsArrayBuffer(file);
      }
    });
    return file;
  } catch (error) {
    console.log(error);
  } finally {
  }
};
 
parseWorker里面then中res


![[SWPUCTF 2021 新生赛]Do_you_know_http](https://img-blog.csdnimg.cn/direct/22630efd93414537938d82a27e9236b5.png)


(两种解法:双指针+排序,哈希)](https://img-blog.csdnimg.cn/direct/8f8ecd5814b7472aa5673342dfb2fddc.png)













