前端实现查询数据【导出】功能
代码实拉到最后。
1. 前端页面是没办法创建文件的,如何实现导出功能?
您提的这个问题非常好,您的理解是正确的:出于安全考虑,浏览器中的前端JavaScript确实无法直接在您的电脑上创建或修改文件。
我们这里的实现方式是一种巧妙的“障眼法”。整个过程分为两步:
-
在内存中生成文件:
xlsx 这个库首先在浏览器的内存里,根据您提供的数据动态地构建出一个完整的Excel文件。这个时候,它还只是内存中的一串二进制数据,并没有真正地写入到您的硬盘里。 -
利用浏览器功能触发下载:
- 代码会动态地创建一个隐藏的下载链接(一个 <a> 标签)。
- 然后将内存中生成的Excel文件数据,转换成一个特殊的URL(Blob URL),并赋给这个链接。
- 最后,代码会自动“点击”这个隐藏的链接。
浏览器接收到这个“点击”指令后,就会像处理普通的文件下载一样,弹出保存文件的对话框,让您选择把这个文件保存在哪里。
所以,整个过程是在内存中生成内容,然后利用浏览器自身的下载功能来实现的,并没有绕过浏览器的安全限制。
2. 为什么Blob URL可以直接在a标签中下载?
您可以把 Blob URL 理解成一个由浏览器创建的临时的、内部的地址。这个地址指向的不是互联网上的某个文件,而是直接指向当前浏览器内存里的一块数据。
整个下载过程是这样的:
-
在内存中创建数据:首先,我们的 xlsx 库在浏览器内存里,把 Excel 文件的所有原始数据准备好。这块数据被称为一个 Blob 对象。
-
生成内部地址:浏览器为内存中的这块 Blob 数据生成一个独一无二的 Blob URL(比如 blob:http://.../一串唯一的ID )。这个 URL 就像一个指向这块内存数据的内部快捷方式,只有当前页面能访问,而且是暂时的。
-
<a> 标签的作用:<a> 标签(链接)的 href 属性原本是用来指定跳转地址的。当它指向一个 Blob URL 时,浏览器知道要去自己的内存里寻找数据。
-
关键在于 download 属性:我们在 <a> 标签上增加了一个 download="文件名.xlsx" 属性。这个属性等于告诉浏览器:“不要试图打开或显示这个链接的内容,而是要把它当作一个文件来下载,并且建议的文件名是这个。”
所以,当我们的代码模拟“点击”这个链接时,浏览器就会按照指令:通过 Blob URL 在内存中找到数据,然后因为看到了 download 属性,就立刻触发标准的下载流程,弹出“另存为”对话框。
这是一种安全、标准的浏览器功能,专门用来处理在前端动态生成的文件。
3. 代码实现
import * as XLSX from 'xlsx'const handleExport = async () => {try {const res = await apis.dataList({params})if (res && res.data && (res.data as DataType[]).length > 0) {const data = (res.data as DataType[]).map((item: DataType) => ({名称: item.name,类型: item.type,说明: item.remark,}))const worksheet = XLSX.utils.json_to_sheet(data)const workbook = XLSX.utils.book_new()XLSX.utils.book_append_sheet(workbook, worksheet, '数据列表')XLSX.writeFile(workbook, '数据列表.xlsx')} else {message.error('没有数据可以导出')}} catch (error) {message.error('操作失败,请重试')}
}