前端导出文件 | fileSaver.js源码阅读

一、学习目标😀

  1. 了解fileSaver.js核心实现
  2. 自己动手实现简易导出功能
  3. 在Vue中如何使用文件

二、源码调试😊

1、fileSave.js库地址:https://github.com/eligrey/FileSaver.js

1、git clone https://github.com/eligrey/FileSaver.js.git

2、cd FileSaver.js-master/ src 目录

3、在src下新建test.html,copy 下面代码

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>Document</title>
	</head>
	<body>
		<button id="btn">下载</button>
		<a href="www.baidu.com" class="anode"></a>
	</body>
	<script src="./FileSaver.js"></script>
	<script>
		console.log(window,'window')
		const btn = document.querySelector("#btn");
		const aNode = document.querySelector(".anode");
		btn.onclick = downLoad;
		function downLoad() {
			var blob = new Blob(["Hello, world!"], { type: "text/plain;charset=utf-8" });
                        debugger
			saveAs(blob, "hello world.txt");
			//aNode.dispatchEvent(new MouseEvent("click"));
		}
	</script>
</html>

2、src目录结构

111111.png

3、在浏览器打开test.html,点击下载按钮,进行代码调试

image.png

进入saveAs函数后可按下一步进行调试,查看代码执行过程。 image.png

fileSaver.js核心代码实现

var saveAs = function (blob, name, opts) {
	var URL = _global.URL || _global.webkitURL;
	//...
	var a = document.createElementNS("http://www.w3.org/1999/xhtml", "a");
	a.download = name;
	// 处理字符串类型二进制
	if (typeof blob === "string") {
		//...  
		a.href = blob;
		click(a); // 触发a锚点的click方法
	} else {
		// 处理图片、文件类型二进制
		a.href = URL.createObjectURL(blob);
		setTimeout(function () {
			URL.revokeObjectURL(a.href);
		}, 4e4); // 40s
		click(a);
	}
};

4、fileSaver强大的一个点在于它兼容了主流的浏览器,下面是我的简易复刻版,省略了对浏览器兼容性考虑,

/**
 * 仿写FileSaver.js文件保存方法
 */

function corsEnabled(url) {
	var xhr = new XMLHttpRequest();
	// use sync to avoid popup blocker
	xhr.open("HEAD", url, false);
	try {
		xhr.send();
	} catch (e) {}
  console.log(xhr.status,'status')
	return xhr.status >= 200 && xhr.status <= 299;
}

// 触发a锚点的click方法
function click(node) {
	try {
		//dispatchEvent向指定事件目标派发Event
		node.dispatchEvent(new MouseEvent("click"));
	} catch (e) {
		// document.createEvent也是创建事件对象。
		var evt = document.createEvent("MouseEvents");
		evt.initMouseEvent(
			"click",
			true,
			true,
			window,
			0,
			0,
			0,
			80,
			20,
			false,
			false,
			false,
			false,
			0,
			null
		);
		node.dispatchEvent(evt);
	}
	//createEvent()可以创建任何类型的事件对象,应用场景更复杂
	//new MouseEvent()只能创建鼠标事件对象
}
function download(url, name, opts) {
	var xhr = new XMLHttpRequest();
	xhr.open("GET", url);
	xhr.responseType = "blob";
	xhr.onload = function () {
		saveAs(xhr.response, name, opts);
	};
	xhr.onerror = function () {
		console.error("could not download file");
	};
	xhr.send();
}
// 初始化环境,判断顶层对象
const _global =
	typeof window !== "undefined" && window.window === window
		? window
		: typeof self === "object" && self.self === self
		? self
		: typeof global === "object" && global.global === global
		? global
		: this;

const saveAs = function (blob, name, opts) {
	var URL = _global.URL; // 浏览器中 window.URL
	// document.createElementNS 创建一个具有指定命名空间 URI 和限定名称的元素
	//创建一个元素而不指定命名空间URI,可使用createElement方法
	var a = document.createElementNS("http://www.w3.org/1999/xhtml", "a");
	name = name || blob.name || "download";

	a.download = name;
	a.rel = "noopener";

	// 字符串类型二进制
	if (typeof blob === "string") {
		a.href = blob;
		if (a.origin !== location.origin) {
			corsEnabled(a.href) ? download(blob, name, opts) : click(a, (a.target = "_blank"));
		} else {
			click(a);
		}
	} else {
		// 创建一个DOMString
		a.href = URL.createObjectURL(blob);
		setTimeout(function () {
			URL.revokeObjectURL(a.href);
		}, 4000);
		setTimeout(function () {
			click(a);
		}, 0);
	}
};

_global.saveAs = saveAs;

// 判断模块被加载,只适用于Node.js环境中,并不能在浏览器端使用。
if (typeof module !== "undefined") {
	module.exports = saveAs;
}

三、小结😳

fileSaver.js提到ES6的globalThis对象,这里简单扩展下。JavaScript 语言存在一个顶层对象,它提供全局环境(即全局作用域),所有代码都是在这个环境中运行。
但是,顶层对象在各种实现里面是不统一的。

  • 浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window。

  • 浏览器和 Web Worker 里面,self也指向顶层对象,但是 Node 没有self。

  • Node 里面,顶层对象是global,但其他环境都不支持。
    同一段代码为了能够在各种环境,都能取到顶层对象,现在一般是使用this关键字,但是有局限性。

  • 全局环境中,this会返回顶层对象。但是,Node.js 模块中this返回的是当前模块,ES6 模块中this返回的是undefined。

  • 函数里面的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象。但是,严格模式下,这时this会返回undefined。

  • 不管是严格模式,还是普通模式,new Function(‘return this’)(),总是会返回全局对象。但是,如果浏览器用了 CSP(Content Security Policy,内容安全策略),那么eval、new Function这些方法都可能无法使用。
    下面是获取顶层对象的方法

// 方法一
(typeof window !== 'undefined'
 ? window
 : (typeof process === 'object' &&
    typeof require === 'function' &&
    typeof global === 'object')
 ? global
 : this);

// 方法二
var getGlobal = function () {
  if (typeof self !== 'undefined') { return self; }
  if (typeof window !== 'undefined') { return window; }
  if (typeof global !== 'undefined') { return global; }
  throw new Error('unable to locate global object');
};

四、在Vue中使用导出文件😊

导出不同的文件使用的MIME类型也不同

import { message } from 'ant-design-vue';

// 导出文件 ,如果二进制数据是后端返回,须在axios添加请求参数 responseType: "blob"
export const exportFileFun = function (res, name,type='application/vnd.ms-excel',fileSuffix='.xlsx') {
  let blob = new Blob([res], {
    type,
  })
  let fileName = name + fileSuffix
  let link = document.createElement('a')
  link.download = fileName
  link.href = window.URL.createObjectURL(blob)
  document.body.appendChild(link)
  link.click()
  setTimeout(() => {
       window.URL.revokeObjectURL(link.href)
  },1000)
  message.success('导出成功')
}

3.1常见 MIME 类型列表

扩展名文档类型MIME 类型
.aacAAC audioaudio/aac
.abwAbiWord documentapplication/x-abiword
.arcArchive document (multiple files embedded)application/x-freearc
.aviAVI: Audio Video Interleavevideo/x-msvideo
.azwAmazon Kindle eBook formatapplication/vnd.amazon.ebook
.binAny kind of binary dataapplication/octet-stream
.bmpWindows OS/2 Bitmap Graphicsimage/bmp
.bzBZip archiveapplication/x-bzip
.bz2BZip2 archiveapplication/x-bzip2
.cshC-Shell scriptapplication/x-csh
.cssCascading Style Sheets (CSS)text/css
.csvComma-separated values (CSV)text/csv
.docMicrosoft Wordapplication/msword
.docxMicrosoft Word (OpenXML)application/vnd.openxmlformats-officedocument.wordprocessingml.document
.eotMS Embedded OpenType fontsapplication/vnd.ms-fontobject
.epubElectronic publication (EPUB)application/epub+zip
.gifGraphics Interchange Format (GIF)image/gif
.htm .htmlHyperText Markup Language (HTML)text/html
.icoIcon formatimage/vnd.microsoft.icon
.icsiCalendar formattext/calendar
.jarJava Archive (JAR)application/java-archive
.jpeg .jpgJPEG imagesimage/jpeg
.jsJavaScripttext/javascript
.jsonJSON formatapplication/json
.jsonldJSON-LD formatapplication/ld+json
.mid .midiMusical Instrument Digital Interface (MIDI)audio/midi audio/x-midi
.mjsJavaScript moduletext/javascript
.mp3MP3 audioaudio/mpeg
.mpegMPEG Videovideo/mpeg
.mpkgApple Installer Packageapplication/vnd.apple.installer+xml
.odpOpenDocument presentation documentapplication/vnd.oasis.opendocument.presentation
.odsOpenDocument spreadsheet documentapplication/vnd.oasis.opendocument.spreadsheet
.odtOpenDocument text documentapplication/vnd.oasis.opendocument.text
.ogaOGG audioaudio/ogg
.ogvOGG videovideo/ogg
.ogxOGGapplication/ogg
.otfOpenType fontfont/otf
.pngPortable Network Graphicsimage/png
.pdfAdobe Portable Document Format (PDF)application/pdf
.pptMicrosoft PowerPointapplication/vnd.ms-powerpoint
.pptxMicrosoft PowerPoint (OpenXML)application/vnd.openxmlformats-officedocument.presentationml.presentation
.rarRAR archiveapplication/x-rar-compressed
.rtfRich Text Format (RTF)application/rtf
.shBourne shell scriptapplication/x-sh
.svgScalable Vector Graphics (SVG)image/svg+xml
.swfSmall web format (SWF) or Adobe Flash documentapplication/x-shockwave-flash
.tarTape Archive (TAR)application/x-tar
.tif .tiffTagged Image File Format (TIFF)image/tiff
.ttfTrueType Fontfont/ttf
.txtText, (generally ASCII or ISO 8859-n)text/plain
.vsdMicrosoft Visioapplication/vnd.visio
.wavWaveform Audio Formataudio/wav
.webaWEBM audioaudio/webm
.webmWEBM videovideo/webm
.webpWEBP imageimage/webp
.woffWeb Open Font Format (WOFF)font/woff
.woff2Web Open Font Format (WOFF)font/woff2
.xhtmlXHTMLapplication/xhtml+xml
.xlsMicrosoft Excelapplication/vnd.ms-excel
.xlsxMicrosoft Excel (OpenXML)application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.xmlXMLapplication/xml 代码对普通用户来说不可读 (RFC 3023, section 3) text/xml 代码对普通用户来说可读 (RFC 3023, section 3)
.xulXULapplication/vnd.mozilla.xul+xml
.zipZIP archiveapplication/zip
.3gp3GPP audio/video containervideo/3gpp audio/3gpp(若不含视频)
.3g23GPP2 audio/video containervideo/3gpp2 audio/3gpp2(若不含视频)
.7z7-zip archiveapplication/x-7z-compressed
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值