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

一、学习目标😀

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

二、源码调试😊

1、fileSave.js库地址:github.com/eligrey/Fil…

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目录结构

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

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

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

进入saveAs函数后可按下一步进行调试,查看代码执行过程。 前端导出文件  |  fileSaver.js源码阅读

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 类型
.aac AAC audio audio/aac
.abw AbiWord document application/x-abiword
.arc Archive document (multiple files embedded) application/x-freearc
.avi AVI: Audio Video Interleave video/x-msvideo
.azw Amazon Kindle eBook format application/vnd.amazon.ebook
.bin Any kind of binary data application/octet-stream
.bmp Windows OS/2 Bitmap Graphics image/bmp
.bz BZip archive application/x-bzip
.bz2 BZip2 archive application/x-bzip2
.csh C-Shell script application/x-csh
.css Cascading Style Sheets (CSS) text/css
.csv Comma-separated values (CSV) text/csv
.doc Microsoft Word application/msword
.docx Microsoft Word (OpenXML) application/vnd.openxmlformats-officedocument.wordprocessingml.document
.eot MS Embedded OpenType fonts application/vnd.ms-fontobject
.epub Electronic publication (EPUB) application/epub+zip
.gif Graphics Interchange Format (GIF) image/gif
.htm .html HyperText Markup Language (HTML) text/html
.ico Icon format image/vnd.microsoft.icon
.ics iCalendar format text/calendar
.jar Java Archive (JAR) application/java-archive
.jpeg .jpg JPEG images image/jpeg
.js JavaScript text/javascript
.json JSON format application/json
.jsonld JSON-LD format application/ld+json
.mid .midi Musical Instrument Digital Interface (MIDI) audio/midi audio/x-midi
.mjs JavaScript module text/javascript
.mp3 MP3 audio audio/mpeg
.mpeg MPEG Video video/mpeg
.mpkg Apple Installer Package application/vnd.apple.installer+xml
.odp OpenDocument presentation document application/vnd.oasis.opendocument.presentation
.ods OpenDocument spreadsheet document application/vnd.oasis.opendocument.spreadsheet
.odt OpenDocument text document application/vnd.oasis.opendocument.text
.oga OGG audio audio/ogg
.ogv OGG video video/ogg
.ogx OGG application/ogg
.otf OpenType font font/otf
.png Portable Network Graphics image/png
.pdf Adobe Portable Document Format (PDF) application/pdf
.ppt Microsoft PowerPoint application/vnd.ms-powerpoint
.pptx Microsoft PowerPoint (OpenXML) application/vnd.openxmlformats-officedocument.presentationml.presentation
.rar RAR archive application/x-rar-compressed
.rtf Rich Text Format (RTF) application/rtf
.sh Bourne shell script application/x-sh
.svg Scalable Vector Graphics (SVG) image/svg+xml
.swf Small web format (SWF) or Adobe Flash document application/x-shockwave-flash
.tar Tape Archive (TAR) application/x-tar
.tif .tiff Tagged Image File Format (TIFF) image/tiff
.ttf TrueType Font font/ttf
.txt Text, (generally ASCII or ISO 8859-n) text/plain
.vsd Microsoft Visio application/vnd.visio
.wav Waveform Audio Format audio/wav
.weba WEBM audio audio/webm
.webm WEBM video video/webm
.webp WEBP image image/webp
.woff Web Open Font Format (WOFF) font/woff
.woff2 Web Open Font Format (WOFF) font/woff2
.xhtml XHTML application/xhtml+xml
.xls Microsoft Excel application/vnd.ms-excel
.xlsx Microsoft Excel (OpenXML) application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.xml XML application/xml 代码对普通用户来说不可读 (RFC 3023, section 3) text/xml 代码对普通用户来说可读 (RFC 3023, section 3)
.xul XUL application/vnd.mozilla.xul+xml
.zip ZIP archive application/zip
.3gp 3GPP audio/video container video/3gpp audio/3gpp(若不含视频)
.3g2 3GPP2 audio/video container video/3gpp2 audio/3gpp2(若不含视频)
.7z 7-zip archive application/x-7z-compressed

原文链接:https://juejin.cn/post/7236672410627358775 作者:树下的少年

(0)
上一篇 2023年5月25日 上午11:12
下一篇 2023年5月26日 上午10:00

相关推荐

发表评论

登录后才能评论