源文件下载保存-如何健壮
download 属性
借助 html5 的新增特性 download
js
/**
* @params url 下载资源路径
* @params name 文件名
*/
function saveAs(url, name) {
var a = document.createElement('a')
a.download = name
a.rel = 'noopener'
a.href = url
a.click()
}
特点
download属性指示浏览器下载 URL 而不是导航到它,因此将提示用户将其保存为本地文件。- 如果属性有一个值,那么此值将在下载保存过程中作为预填充的文件名。
- 此属性对允许的值没有限制,但是 / 和 \ 会被转换为下划线。
- 大多数文件系统限制了文件名中的标点符号,故此,浏览器将相应地调整建议的文件名。
- 此属性仅适用于同源 URL
a.click()能兼容所有浏览器吗
js
function click(node) {
try {
node.dispatchEvent(new MouseEvent('click'))
} catch (e) {
var e = document.createEvent('MouseEvent')
e.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null)
node.dispatchEvent(evt)
}
}
Blob
- 它表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。
- File 接口基于 Blob,继承了 blob 的功能并将其扩展使其支持用户系统上的文件。
- 非 blob 对象转 Blob,请使用 Blob()构造函数;创建子集 blob,用 slice()方法,大文件切片就靠它了。
js
function download(url, name) {
var xhr = new XMLHttpRequest()
xhr.open('GET', url)
xhr.responseType = 'blob'
xhr.onload = function () {
var url = URL.createObjectURL(xhr.response)
saveAs(url, name)
setTimeout(function () {
URL.revokeObjectURL(url)
}, 4e4) // 40s
}
xhr.onerror = function () {
console.error('could not download file')
}
xhr.send()
}
新增个是否支持跨域的判断
js
function corsEnabled(url) {
var xhr = new XMLHttpRequest()
xhr.open('HEAD', url, false)
try {
xhr.send()
} catch (e) {}
return xhr.status >= 200 && xhr.status <= 299
}
请求是否允许 cors 是同步的。
js
corsEnabled(url) ? download(url, name) : saveAs(url, name)
msSaveOrOpenBlob
IE10 来了,莫慌。它提供了 msSaveBlob 和 msSaveOrOpenBlob 两方法允许用户在客户端上保存文件,就像从 Internet 下载文件,这也是为啥此类文件能保存到下载文件夹。这两方法还是存在一些区别:
- msSaveBlob 只提供一个保存按钮
- msSaveOrOpenBlob 提供保存和打开按钮
js
/**
*
* @params blob :Blob对象
* @params name :文件名
*/
function saveAs(blob, name, opts) {
if ('msSaveOrOpenBlob' in navigator) {
navigator.msSaveOrOpenBlob(bom(blob, opts), name)
}
}
function bom(blob, opts) {
if (typeof opts === 'undefined') opts = { autoBom: false }
else if (typeof opts !== 'object') {
opts = { autoBom: !opts }
}
// 为UTF-8 XML和text/*类型(包括HTML)预先准备BOM表
// 浏览器会自动将UTF-16 U+FEFF转换为EF BB BF
if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
return new Blob([String.fromCharCode(0xfeff), blob], { type: blob.type })
}
return blob
}
FileReader
- FileReader 对象允许 Web 应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。
- File 对象来自 input 元素选择文件返回的 FileList 对象,也可以是拖拽生成的 DataTransfer 对象,或者是 Canvas 上执行 mozGetAsFile()方法返回的结果.
- FileReader 仅用于以安全的方式从用户(远程)系统读取文件内容 它不能用于从文件系统中按路径名简单地读取文件.
js
function saveAs() {
var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent)
var reader = new FileReader()
reader.onloadend = function () {
var url = reader.result
url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;')
window.location.href = url
}
reader.readAsDataURL(blob)
}
4 种方式存在的情况下如何排优先级呢?
- download
- msSaveOrOpenBlob
- FileReader