前端文件下载实现方案,Blob对象为你实现任意文件下载


前言

本文主要介绍了如何使用 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对象 方便实现各种文件下载需求。

猜你喜欢

转载自blog.csdn.net/SmallTeddy/article/details/134265816