文章目录
- 前言
- 一、Blob是什么?
- 二、生成Blob对象
- 三、请求处理
- 1、请求封装
- 2、根据后端接口配置
- 四、工具函数
- 五、项目中实际使用
- 六、优化下载
前言
本文主要介绍了如何使用 Blob对象
在前端实现文件下载的功能。
文中首先介绍了什么是 Blob对象
,它表示一个二进制大型对象,可以用来表示文件或二进制数据。然后详细讲解了几种生成 Blob对象
的方式,以及如何通过 createObjectURL
方法生成一个对象 URL
,设置到 a 标签
的 href
属性实现文件下载。文末还提到了一些优化下载体验的方法,比如设置 download
属性、使用 click
方法触发下载等。
掌握 Blob
的使用可以实现强大的前端文件下载、上传、二进制数据处理功能,是很重要的能力。本文内容通俗易懂,可以帮助读者快速理解 Blob
的用法。
一、Blob是什么?
Blob(Binary Large Object)
表示二进制类型的大对象,可以用来表示文件或二进制数据。在前端中,我们可以通过 Blob对象
生成一个文件对象,然后通过创建一个 a标签
实现文件下载。
二、生成Blob对象
可以通过以下几种方式生成一个 Blob对象
:
// 从字符串生成Blob对象
const blob = new Blob(['hello world'])
// 从数组生成Blob对象
const blob = new Blob([new Uint8Array([1,2,3])])
// 从另一个blob生成
const newBlob = blob.slice()
// 从canvas生成
canvas.toBlob(callback)
生成的 Blob对象
表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream
来用于数据处理。
三、请求处理
1、请求封装
在 fileRequest.ts
文件中
import axios from 'axios'
// 创建axios实例
const fileRequest = axios.create({
timeout: 30 * 1000, // 请求超时时间
responseType: 'blob', // *重点*
withCredentials: true
})
// request 拦截器
fileRequest.interceptors.request.use(
// 省略若干
)
// response 拦截器
fileRequest.interceptors.response.use(
// 省略若干
)
export default fileRequest
2、根据后端接口配置
在 fileApi.ts
文件中
import fileRequest from './utils/fileRequest'
// 文件下载接口
export function postFileDownloadUrl(data = {}) {
return fileRequest({
url: '后端url',
method: 'POST',
data
})
}
四、工具函数
我们封装一个 download
工具函数,用来处理后端返回的任意二进制文件下载
在 file.ts
文件中
import { ElMessage } from "element-plus";
import { blobType } from './blobType'
export function download(file: any, fileType: string, fileName?: string) {
if (!fileName) {
const timeStr = new Date().getTime()
fileName = `${timeStr}`
}
const type = formatFileType(fileType)
if (!type) return ElMessage.warning('暂不支持此格式!')
const blob = new Blob([file], { type })
const downloadElement = document.createElement('a')
const href = window.URL.createObjectURL(blob) // 创建下载的链接
downloadElement.href = href
downloadElement.download = fileName // 下载后文件名
document.body.appendChild(downloadElement)
downloadElement.click() // 点击下载
document.body.removeChild(downloadElement) // 下载完成移除元素
window.URL.revokeObjectURL(href) // 释放掉blob对象
}
export function formatFileType(fileFormat: string) {
return blobType[fileFormat]
}
export function blobToFileReader(blob: any, callback: any) {
if (!blob.size) return ElMessage.warning('暂无资源!')
if (blob.type !== 'application/json') return callback(blob)
const fr: any = new FileReader()
fr.onloadend = function () {
try {
callback(JSON.parse(fr.result))
} catch (err) {
ElMessage.warning('资源数据有误!')
}
}
fr.readAsText(blob)
}
在 blobType.ts
文件中(用来匹配文件的下载格式)
export const blobType: Record<string, string> = {
aac: 'image/audio/aac',
abw: 'application/x-abiword',
arc: 'application/x-freearc',
avi: 'video/x-msvideo',
azw: 'application/vnd.amazon.ebook',
bin: 'application/octet-stream',
bmp: 'image/bmp',
bz: 'application/x-bzip',
bz2: 'application/x-bzip2',
csh: 'application/x-csh',
css: 'text/css',
csv: 'text/csv',
doc: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
eot: 'application/vnd.ms-fontobject',
epub: 'application/epub+zip',
exe: 'application/x-msdownload',
gif: 'image/gif',
htm: 'text/html',
html: 'text/html',
ico: 'image/vnd.microsoft.icon',
ics: 'text/calendar',
jar: 'application/java-archive',
jpeg: 'image/jpeg',
jpg: 'image/jpeg',
js: 'text/javascript',
json: 'application/json',
jsonld: 'application/ld+json',
mid: 'audio/midi audio/x-midi',
midi: 'audio/midi audio/x-midi',
mjs: 'text/javascript',
mp3: 'audio/mpeg',
mpeg: 'video/mpeg',
mpkg: 'application/vnd.apple.installer+xml',
odp: 'application/vnd.oasis.opendocument.presentation',
ods: 'application/vnd.oasis.opendocument.spreadsheet',
odt: 'application/vnd.oasis.opendocument.text',
oga: 'audio/ogg',
ogv: 'video/ogg',
ogx: 'application/ogg',
otf: 'font/otf',
png: 'image/png',
pdf: 'application/pdf',
ppt: 'application/vnd.ms-powerpoint',
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
rar: 'application/x-rar-compressed',
rtf: 'application/rtf',
sh: 'ima',
svg: 'image/svg+xml',
swf: 'application/x-shockwave-flash',
tar: 'application/x-tar',
tif: 'image/tiff',
tiff: 'image/tiff',
ttf: 'font/ttf',
txt: 'text/plain',
vsd: 'application/vnd.visio',
wav: 'audio/wav',
weba: 'audio/webm',
webm: 'video/webm',
webp: 'image/webp',
woff: 'font/woff',
woff2: 'font/woff2',
xhtml: 'application/xhtml+xml',
xls: 'application/vnd.ms-excel',
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
xml: 'text/xml',
xul: 'application/vnd.mozilla.xul+xml',
zip: 'application/zip',
'3gp': 'video/3gpp',
'3g2': 'video/3gpp2',
'7z': 'application/x-7z-compressed'
}
五、项目中实际使用
经过上面的封装,在项目中使用二进制流下载就非常的简单了,具体示例代码如下:
import { postFileDownloadUrl } from '@/api/fileApi'
import { download } from '@/utils/file'
const downloadFileClick = () => {
const parmas = {
// 根据接口设置请求参数
}
postFileDownloadUrl(params).then(res => {
// 按照download(二进制数据, 文件格式, 文件名称)使用
download(res, pdf, 'test')
})
}
六、优化下载
为了获得更好的下载体验,我们可以进一步优化:
- 为
a标签
添加download
属性,会将文件名设置为该属性值 - 使用
click
触发下载,无需用户手动点击 - 对
Blob数据
加工,比如设置类型、压缩等 - 下载完成后主动释放
Object URL
,避免内存泄露
通过以上优化,我们就可以通过Blob对象
方便实现各种文件下载需求。