JS-文件下载

1,021 阅读3分钟

通过ajax请求后端生成的文件流之后,创建BLOB文件进行下载,在PC端和移动安卓端都可以实现下载到本地

步骤

通过request,responseType的值为 'arraybuffer',请求对应的文件流

uni.request({
  ...handleRes,
  responseType: 'arraybuffer',
  success(res) {
    // console.log(res, '返回数据');
              // 这是返回的文件流
    const file = res.data;
    
  },
  fail() {
    uni.hideLoading();
    
  }
})

通过将文件流转成blob对象

let blob = null;
if (headerDis.indexOf(tyepList.toString()) != -1) {
  blob = new Blob([file], {
    type: 'application/octet-stream;charset=UTF-8',
  })
} else {
  blob = new Blob([file], {
    type: headerInfo['content-type'] ||
      'application/octet-stream;charset=UTF-8',
  })
}

通过创建A链接,通过download属性进行下载

async linkTodownloadFile(blob, fName) {
		if (window.navigator.msSaveOrOpenBlob) {
			window.navigator.msSaveBlob(blob, fName);
			return false;
		}
		const url = window.URL.createObjectURL(blob)
		const link = document.createElement('a')
		link.style.display = 'none'
		link.href = url;
		link.setAttribute('download', fName)
		document.body.appendChild(link)
		if (document.all) {
			link.click();
		} else {
			// 兼容 Firfox
			const evt = document.createEvent('MouseEvents');
			evt.initEvent('click', true, true);
			link.dispatchEvent(evt);
		}
		document.body.removeChild(link) // 下载完成移除元素
		window.URL.revokeObjectURL(url);
	}

demo

uni.request({
  url : 'xxx',
  responseType: 'arraybuffer',
  success(res) {
    // console.log(res, '返回数据');
    const file = res.data;
    const headerInfo = res.header;
    /** 获取文件名称 */
    let fName = '';
    /** 判断是否为可自定义类型还是默认 */
    const tyepList = ['pdf'];

    const headerDis = headerInfo['content-disposition'];

    if (headerDis) {
      const requestFileInfo = headerDis.split(';')[1];
      if (store.state.app.SYSTEM_INFO.platform == 'ios') {
        if (headerDis.indexOf(tyepList.toString()) != -1) {
          fName = requestFileInfo;
        } else {
          fName = requestFileInfo.split('.')[0];
        }

      } else {
        fName = requestFileInfo;
      }
    } else {
      /** 判断文件是否有类型,没有就拿效应头 */
      const fType = file.type || headerInfo['content-type'].split(';')[0];
      for (const key in fileTypeConfig) {
        if (fileTypeConfig[key].indexOf(fType) != -1) {
          if (store.state.app.SYSTEM_INFO.platform == 'ios') {
            fName = `${fileName}`;
          } else {
            fName = `${fileName}.${key}`;
          }
          break
        }
      }
    }

    /** 开始下载 */
    let blob = null;

    if (headerDis.indexOf(tyepList.toString()) != -1) {
      blob = new Blob([file], {
        type: 'application/octet-stream;charset=UTF-8',
      })
    } else {
      blob = new Blob([file], {
        type: headerInfo['content-type'] ||
          'application/octet-stream;charset=UTF-8',
      })
    }

    /** 判断是否为JSON 做逻辑处理 */
    if (fName.indexOf('json') != -1) {
      //通过FileReader读取数据
      const reader = new FileReader();
      // reader.readAsBinaryString(blob);
      reader.readAsText(blob, 'utf8');
      reader.onload = function() {
        var content = JSON.parse(this.result); //这个就是解析出来的数据
        if (content.code == 200) {
          that.linkTodownloadFile(blob, fName);
          resolve();
        } else {
          isLoading && uni.hideLoading();
          common.toast(content.msg || 400);
        }
      }
    } else {
      that.linkTodownloadFile(blob, fName);
      resolve();
    }
  },
  fail() {
    reject();
  }
})

下载文件分类

链接下载

// 调用api示例,返回一个url
await url= await Api.getDownloadUrl({
    data: {  something }
});
function jsDownload(url){
	// 生成一个a标签
	var a = document.createElement('a');
	document.body.appendChild(a);
	// 如果是完整的链接
	a.href = url;
	// 如果只是返回了后半段的链接
	// a.href = location.origin + url;
	// 静态文件的话不一定会生效,所以后端要把名字起好
	a.download = '文件名'+'.xls';
	// 触发点击
	a.click();
	// 用完就删掉,避免越加越多
	document.body.removeChild(a);
}
jsDownload(url);

二进制流下载

需要设置 responseType: ‘blob’

// 以 axios为例,其它的插件也差不多,这里主要讲收到之后怎么处理
axios.get(url,{
	responseType:'blob',
}).then(res => {
	downloadFile(res.data)
})
// 转化为blob对象下载
function downloadFile(data){
	const blob = new Bolb([data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'})
	// 把blob对象转成一个可下载的链接;注意:window.URL或者URL都行
	let url = URL.createObjectURL(blob);
	jsDownload(url);
	// 下载完记得删掉链接,延时更保险;4E4就是40秒
	setTimeout(function () { URL.revokeObjectURL(url) }, 4E4)
}
为什么下载文件加FileReader

FileReader是js读取文件的API,在下载文件使用的时候,作用跟URL.createObjectURL是一样的,都是为了生成a标签能下载的链接,但是它跟URL.createObjectURL的区别就是,URL.createObjectURL苹果不兼容

//  下面的代码只是示意,要做兼容用后面介绍的file-saver.js
var reader = new FileReader()
reader.onloadend = function () {
	var url = reader.result
	url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;')
	jsDownload(url)
}
reader.readAsDataURL(blob)

使用file-saver.js

npm install file-saver --save
# 如使用TS开发,可安装file-saver的TypeScript类型定义
npm install @types/file-saver --save-dev
import FileSaver from 'file-saver';
 
FileSaver saveAs(Blob/File/Url,fileType)
// 参数1:支持的类型:blob(二进制)、File(文件)、Url(url链接)
// 参数2:文件类型

保存文本

// 保存文本
saveText() {
    // 创建二进制文件
    let blob = new Blob(['保存一个文本'],{type: 'text/plain;charset=utf-8'});
    FileSaver.saveAs(blob,'a.txt');
}

保存url

 saveUrl() {
     FileSaver.saveAs('https://ppt.1ppt.com/uploads/soft/2202/1-2202231A334.zip', 'a.zip');
 }

保存canvas

var canvas = document.getElementById("my-canvas");
canvas.toBlob(function(blob) {
    FileSaver.saveAs(blob, "pretty image.png");
});

保存文件

 saveFile() {
      let file = new File(['保存一个文件'],'a.txt',{type: 'text/plain;charset=utf-8'});
      FileSaver.saveAs(file);
 }