本例使用react + antd 实现 核心代码没啥区别
核心步骤
- 读取文件,拿到
file
对象 - 处理file中的数据,其中分别包括文本数据以及图片数据
- 首先使用
Upload
组件拿到文件的file
对象
<Upload
accept=".xlsx"
beforeUpload={(file) => {
// 这就拿到了file对象 handleUpload为处理file对象的方法
handleUpload(file);
return false;
}}
showUploadList={false}
>
添加
</Upload>
- 处理
file
中的数据
举一个简单的例子,这是一个xlsx
文件
我们引入xlsx这个库,对读取的信息进行处理
import * as XLSX from "xlsx";
......
const handleUpload = async (file: Blob) => {
// 异步读取文件
const reader = new FileReader();
reader.onload = (e: any) => {
// 格式化数组
const data = new Uint8Array(e.target.result);
// 读取文件内容
const workbook = XLSX.read(data, {
type: "array" });
// 如果指定了 sheetName,则将其用于查找工作表;否则,使用默认的第一个工作表。
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
// 将工作表数据转换为 JSON 格式
const jsonData: any = XLSX.utils.sheet_to_json(worksheet, {
header: 1 });
// 判断所选工作区的内容是否为空
if (jsonData.length > 0) {
const newData: any[] = [];
// 第一行默认认为是表头 除开第一行以外都是数据
jsonData.slice(1).forEach((item, itemIndex: number) => {
if (item.length === 0) return false;
const obj: any = {
key: itemIndex };
jsonData[0].forEach((header: any, index: any) => {
obj[header] = item[index];
});
newData.push(obj);
});
console.log(newData)
} else {
console.log("没数据");
}
}
reader.readAsArrayBuffer(file);
}
可以看到打印的数据中, 除了图片列,其他的文本列的数据都正常拿到了
而头像的数据没有返回图片的信息,仅仅是一个可能是id的字符串,既然是id
,那说明这个图片一定可以根据这个id
找到
根据xlsx
这种类型的文件,官方给出解释
那么我们可以通过jszip这个库来对xlsx
文件进行解析,从而可以拿到所有的xml
文件。
try {
const zip = new JSZip();
let zipLoadRes = await zip.loadAsync(file);
console.log(zipLoadRes);
} catch (err) {
console.log("err", err);
}
通过打印数据,可以看到里面出现了图片信息
可以看到xl
文件夹下面包含了
打开其中的cellimages.xml
文件可以看到其中几条数据和我们前面拿到的id
是一样的,同时各个id
还对应了一个rid
而在 xl/_rels/cellimages.xml.rels
文件下,对应的 rid
下,又分别对应着image
的名称
那么我们就可以一步一步的来根据id
,组合出一个id
对应的图片对象,代码如下:
let imageList: IImageInfo[] = [];
let implantBlobList = [];
/** @name 针对嵌入了单元格的图片 */
const implantFile = zipLoadRes.files["xl/cellimages.xml"];
if (implantFile) {
const xmlContent = await implantFile.async("string");
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlContent, "text/xml");
if (xmlDoc.getElementsByTagName("parsererror").length > 0) {
console.error(
"XML 解析错误:",
xmlDoc.getElementsByTagName("parsererror")[0].textContent
);
return;
}
// 查找所有的 <etc:cellImage> 标签
const cellImage = xmlDoc.querySelectorAll("etc\\:cellImage, cellImage");
cellImage.forEach((cellImage) => {
// 查找 <xdr:pic> 标签
const picElement = cellImage.querySelector("xdr\\:pic, pic");
if (picElement) {
let obj: Partial<IImageInfo> = {
};
// 查找 <xdr:nvPicPr> 标签
const nvPicPrElement = picElement.querySelector(
"xdr\\:nvPicPr, nvPicPr"
);
// 查找 <xdr:blipFill> 标签
const blipFillElement = picElement.querySelector(
"xdr\\:blipFill, blipFill"
);
if (nvPicPrElement && blipFillElement) {
// 查找 <a:blip> 标签
const blipElement = blipFillElement.querySelector(
"a\\:blip, blip"
);
if (blipElement) {
const embedValue = blipElement.getAttribute("r:embed") || "";
obj.rid = embedValue;
}
// 查找 <xdr:cNvPr> 标签
const cNvPrElement = nvPicPrElement.querySelector(
"xdr\\:cNvPr, cNvPr"
);
if (cNvPrElement) {
const nameValue = cNvPrElement<