Skip to content
文章目录

源文件下载保存-如何健壮

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 种方式存在的情况下如何排优先级呢?

  1. download
  2. msSaveOrOpenBlob
  3. FileReader

相关文章

前端实现打包下载

接口返回 blob 和 json 两种格式时-前端处理方式

a 标签 download 属性无效

参考资料

源文件下载保存-如何健壮