前端实现文件下载

396 阅读2分钟

前端实现文件下载

浏览器端实现点击按钮下载图片

移动端不兼容
移动端不兼容
移动端不兼容

老版本Google浏览器可以a标签直接下载,新版本会打开图片,只有图片同源才会直接下载
老版本Google浏览器可以a标签直接下载,新版本会打开图片,只有图片同源才会直接下载
老版本Google浏览器可以a标签直接下载,新版本会打开图片,只有图片同源才会直接下载

现在新版的浏览器,点击a标签进行下载图片时,往往不会按照预期实现图片的下载功能,而是会在新的窗口打开图片,代码如下:

<a href="https://static001.geekbang.org/resource/image/fa/af/face2257c62b291620a1750b4cdaf4af.jpg?x-oss-process=image/resize,m_fill,h_400,w_818" download>下载</a>

要想实现点击按钮下载图片,常见的做法是后端配置请求头来实现资源的下载,但是现在一般都前后端分离了,并且很多图片在oss上,不能直接修改通用的请求配置

当请求的图片是同源的时,可以直接通过a标签实现下载

// 网址
https://www.xxx.com
// 图片地址
https://www.xxx.com/image/1.png

当图片是cdn地址时,配置图片的请求头为当前域名也可以

// 极客时间地址
https://time.geekbang.org/
// 极客时间图片地址
https://static001.geekbang.org/resource/image/ab/9f/ab17ecf8fdb768db1362ec72c2f8ce9f.jpg
// 图片请求头配置
referer: https://time.geekbang.org/

当图片不再跨域时,可以使用的方法就比较多了:

通过blob流来实现下载:

const imgDownload = (src, name) => {
  const canvas = document.createElement('canvas');
  const img = document.createElement('img');
  img.onload = () => {
    canvas.width = img.width;
    canvas.height = img.height;
    const context = canvas.getContext('2d');
    context.drawImage(img, 0, 0, img.width, img.height);
    canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
    canvas.toBlob(
      (blob) => {
        const link = document.createElement('a');
        link.href = window.URL.createObjectURL(blob);
        link.download = name || 'download'; // resource name
        link.click();
      },
      '0.95',
    );
  };
  img.setAttribute('crossOrigin', 'Anonymous');
  img.src = src;
}

imgDownload(url, 1.png);

通过FileSaver.js实现下载

import { saveAs } from 'file-saver';

saveAs(url, 1.png)

浏览器实现批量下载在线图片到本地同一个文件夹并压缩

import JSZip from 'jszip';
import { saveAs } from 'file-saver';

const imgBlob = (src) => {
  const canvas = document.createElement('canvas');
  const img = document.createElement('img');
  img.setAttribute('crossOrigin', 'Anonymous');
  img.src = src;
  return new Promise((resolve) => {
    img.onload = () => {
      canvas.width = img.width;
      canvas.height = img.height;
      const context = canvas.getContext('2d');
      context.drawImage(img, 0, 0, img.width, img.height);
      canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
      canvas.toBlob(
        (blob) => {
          resolve(blob);
        },
        '0.95',
      );
    };
  });
};

const downloadImgs = async (urls, name) => {
    const zip = new JSZip();
    const imgs = zip.folder('images');

    const blobs = urls.map(async (url) => {
      const blob = await imgBlob(url);
      return blob;
    });
    blobs.forEach((blob, index) => {
      imgs.file(`${index}.png`, blob);
    });
    zip.generateAsync({ type: 'blob' }).then((content) => {
      saveAs(content, `${name || 'example'.zip}`);
    });
  };