加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程 > 正文

JavaScript如何做下载文件的功能?

发布时间:2022-03-01 01:18:51 所属栏目:编程 来源:互联网
导读:JavaScript怎样做下载文件的功能?有很多网站都会有提供下载文件的功能,小编觉得比较使用,因此这篇文章就给大家分享一下JS实现前端下载文件功能的具体代码,感兴趣的朋友可以参考。 在 html5 中,a 标签新增了 download 属性,包含该属性的链接被点击时,
   JavaScript怎样做下载文件的功能?有很多网站都会有提供下载文件的功能,小编觉得比较使用,因此这篇文章就给大家分享一下JS实现前端下载文件功能的具体代码,感兴趣的朋友可以参考。
 
  在 html5 中,a 标签新增了 download 属性,包含该属性的链接被点击时,浏览器会以下载文件方式下载 href 属性上的链接。示例:
 
  <a href="https://www.baidu.com" rel="external nofollow" download="baidu.html">下载</a>
  1. 前端 js 下载实现与示例
 
  通过 javascript 动态创建一个包含 download 属性的 a 元素,再触发点击事件,即可实现前端下载。
 
  代码示例:
 
  function download(href, title) {
      const a = document.createElement('a');
      a.setAttribute('href', href);
      a.setAttribute('download', title);
      a.click();
  }
  说明:
 
  href 属性设置要下载的文件地址。这个地址支持多种方式的格式,因此可以实现丰富的下载方法。
  download 属性设置了下载文件的名称。但 href 属性为普通链接并且跨域时,该属性值设置多数情况下会被浏览器忽略。
  1.1 普通连接下载示例
 
  // 下载图片
  download('https://lzw.me/images/gravatar.gif', 'lzwme-gravatar');
  // 下载一个连接
  download('https://lzw.me', 'lzwme-index.html');
  1.2 href 为 data URIs 示例
  data URI 是前缀为 data:scheme 的 URL,允许内容创建者在文档中嵌入小文件。数据URI由四个部分组成:前缀(数据:),指示数据类型的MIME类型,如果非文本则为可选的base64令牌,数据本身:
 
  data:[<mediatype>][;base64],<data>
  链接的 href 属性为 data URIs 时,也可以实现文件内容的下载。示例:
 
  download('data:,Hello%2C%20World!', 'data-uris.txt');
  download('data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D', 'data-uris.txt');
  1.3 canvas 下载示例
  对于 canvas 可以通过 toDataURL 方法取得 data URIs 格式的内容。
 
  1.4 二进制内容下载
  URL.createObjectURL 方法会根据传入的参数创建一个指向该参数对象的 URL。新的对象 URL 指向执行的 File 对象或者是 Blob 对象。
 
  URL.createObjectURL 的参数是 File 对象或者 Blob 对象,File 对象也就是通过 input[type=file] 选择的文件,Blob 对象是二进制数据。
 
  将URL.createObjectURL 返回值设为 href 属性的值,即可实现二进制内容下载。示例:
 
  const content = 'Welcome to lzw.me!';
  const blob = new Blob([content]);
  const href = URL.createObjectURL(blob);
  download(href, 'download-text.txt');
  URL.revokeObjectURL(href);
  1.5 前端下载方法示例
  综合上述讨论,这里给出一个前端实现下载的 saveAs 方法的 TypeScript 示例:
 
  /**
   * 通过创建 a dom 对象方式实现前端文件下载
   * @param href 要下载的内容链接。当定义了 toBlob 时,可以为纯文本或二进制数据(取决于 toBlob 格式
   * @param fileName 下载后的文件名称
   * @param toBlob 如设置该参数,则通过 blob 方式将 href 转换为要保存的文件内容,该参数将入参为 new Blob([href], toBlob) 的第二个参数
   * @example
   * ```js
   * saveAs('abc', 'abc.txt', {});
   * saveAs('data:,Hello%2C%20World!', 'hello.txt');
   * saveAs('https://lzw.me/images/avatar/lzwme-80x80.png', 'lzwme-logo.png');
   * ```
   */
  export function saveAs(href: string | Blob, fileName?: string, toBlob?: PlainObject) {
   const isBlob = href instanceof Blob || toBlob;
   if (!fileName && typeof href === 'string' && href.startsWith('http')) {
    fileName = href.slice(href.lastIndexOf('/') + 1);
   }
   fileName = decodeURIComponent(fileName || 'download');
   if (typeof href === 'string' && toBlob) href = new Blob([href], toBlob);
   if (href instanceof Blob) href = URL.createObjectURL(href);
   const aLink = document.createElement('a');
   aLink.setAttribute('href', href);
   aLink.setAttribute('download', fileName);
   aLink.click();
   // const evt = document.createEvent("HTMLEvents");
   // evt.initEvent("click", false, false);
   // aLink.dispatchEvent(evt);
   if (isBlob) setTimeout(() => URL.revokeObjectURL(aLink.href), 100);
   return aLink;
  }
  2.检测浏览器是否支持 download 属性
 
  download 属性为 html5 新增内容,浏览器支持情况可参考:http://caniuse.com/#feat=download
 
  <img src="https://lzw.me/wp-content/uploads/2017/04/a-download.png" alt="" width="879" height="346" class="aligncenter size-full wp-image-2330" />
 
  判断浏览器是否支持该属性,只需要检测 a 标签是否存在 download 属性。示例:
 
  const downloadAble = 'download' in document.createElement('a');
  对于不支持的浏览器,只能另想他法或者予以降级处理了。
 
  3.使用 serviceWorker 和 fetch API 代理实现
 
  前端下载更多的需求是因为内容产生于前端。那么可以在后端实现一个这样的 API ,它在接收到前端发出的内容后返回下载格式的数据。这种实现就不存在浏览器兼容问题。
 
  利用 serviceWorker 和 fetch API 截拦浏览器请求,只需实现好约定逻辑,也可实现这种功能需求。示例:
 
  在页面中,通过 fetch API 构造请求:
 
  fetch('lzwme.txt', {
      isDownload: true,
      body: {
          data: new Blob('hi!')
      }
  })
  在 serviceWorker 中,截拦附带 isDownload 头信息的请求,构造下载回应:
 
  self.addEventListener('fetch', function(event) {
      const req = event.request;
      if (!req.headers.get('isDownload')) {
          retrun fetch(req);
      }
      const filename = encodeURIComponent(req.url);
      const contentType = req.headers.get('Content-Type') || 'application/force-download';
      const disposition = "inline;filename=" + filename + ";filename*=utf-8''" + filename
      const myBody = req.headers.get(body).data;
      event.respondWith(
          new Response(myBody, {
              headers: {
                  'Content-Type': contentType,
                  'Content-Disposition': disposition
              }
          })
      );
  });
  4 使用 ajax (xhr与fetch API) 方式下载服务器文件
 
  以上主要讨论的是纯前端实现下载保存文件的方法。对于下载服务器文件,最简的方式就是 window.open(url) 和 location.href=url 了,但是其的弊端也很明显,当出错时整个页面都会挂掉,而且也无法获得下载状态与进度,下载时间稍长时体验相当不好。
 
  下面介绍一下使用 xhr 和 fetch API 实现文件下载的方法。其主要思路为:将请求结果设为 Blob 类型,然后采用前端下载保存 Blob 类型数据的方式实现下载。
 
  4.1 使用 xhr 下载远程服务器文件
  代码示例:
 
  /** 前端下载/保存文件 */
  function saveAs(href, fileName) {
    const isBlob = href instanceof Blob;
    const aLink = document.createElement('a');
    aLink.href = isBlob ? window.URL.createObjectURL(href) : href;
    aLink.download = fileName;
    aLink.click();
    if (isBlob) setTimeout(() => URL.revokeObjectURL(aLink.href), 100);
  }
  function xhrDownload(url, options = {}) {
    options = Object.assign({ method: 'get', headers: {} }, options);
    return new Promise((reslove, reject) => {
      const xhr = new XMLHttpRequest();
      xhr.responseType = 'blob'; // options.responseType;
      if (options.headers) {
        for (const key in options.headers) xhr.setRequestHeader(key, options.headers[key]);
      }
      xhr.onload = () => {
        // 从 Content-Disposition 中获取文件名示例
        const cd = xhr.getResponseHeader('Content-Disposition');
        if (cd && cd.includes('fileName') && !options.fileName) options.fileName = cd.split('fileName=')[1];
        options.fileName = decodeURIComponent(options.fileName || 'download-file');
        if (+xhr.status == 200) {
          saveAs(xhr.response, options.fileName);
          reslove(options.fileName);
  使用 fecth API 下载远程服务器文件
 
  function fetchDownload(url, options = {}) {
    options = Object.assign({ credentials: 'include', method: 'get', headers: {} }, options);
    return fetch(url, options).then(response => {
      return response.blob().then(blob => {
        if (!blob || !blob.size) return Promise.reject('empty');
        // 从 Content-Disposition 中获取文件名示例
        const cd = response.headers.get('Content-Disposition');
        if (cd && cd.includes('fileName') && !options.fileName) options.fileName = cd.split('fileName=')[1];
        options.fileName = decodeURIComponent(options.fileName || 'download-file');
        saveAs(blob, options.fileName);
        return options.fileName;
      });
    });
  }
  // 测试
  fetchDownload('https://lzw.me/images/avatar/lzwme-80x80.png', {
      // method: 'post',
      // headers: {
      //   'Content-Type': 'application/json'
      // },
      // body: JSON.stringify({
      //   pageSize: 100000,
      //   startPage: 0
      // })
    })

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读