Window下载

实现原理:直接用浏览器访问下载链接,唤起浏览器下载功能

window.location.href = '下载链接';
// 或者
window.open('下载链接');

缺点:无法(从前端)自定义下载文件名,下载可预览文件(图片,音乐、视频等)时,会跳转新的界面

A标签下载

实现原理:创建一个a标签,然后点击它,即把下面的标签用js创建出来

<a href="下载链接" download="文件名(如:a.zip)">下载</a>

a标签download+url

const a = document.createElement('a')
a.href = '下载链接'
a.download = '文件名'
a.style.display = 'none'
a.target = 'downloadFile'
document.body.appendChild(a) // 兼容火狐 
a.click()
document.body.removeChild(a) // 移除a标签

缺点:下载可预览文件时,会跳转新的界面,对于跨域请求download属性会失效,也就是说无法自定义下载文件名

window.URL+blob

下载文件

由于上面是方法会打开新的界面,所以我们需要对下载链接进行一些处理,比如转为blob格式:

    // 这里需要发送一次请求将下载地址里的文件转为blob格式,进行下载(发送请求时同样会存在跨域问题,如果跨域的话需要在nginx配置代理)
    const blob = await fetch('下载链接').then(res => res.blob())
    content = window.URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.href = content
    a.download = '文件名'
    document.body.appendChild(a) // 兼容火狐 
    a.click()
    document.body.removeChild(a) // 移除a标签
    window.URL.revokeObjectURL(content)  // 释放content对象

也可以用ajax请求转为blob格式:

      const x = new window.XMLHttpRequest()
      x.open('GET', '下载链接', true)
      x.responseType = 'blob'
      x.onload = () => {
          const content = window.URL.createObjectURL(x.response)
          const a = document.createElement('a')
          a.href = content
          a.download = '文件名'
          document.body.appendChild(a) // 兼容火狐 
          a.click()
          document.body.removeChild(a) // 移除a标签
          window.URL.revokeObjectURL(content)  // 释放content对象
      }
      x.send()

自然也可以发送axios请求:

  axios({
    method: 'get',
    url: '下载链接'
    responseType: 'blob',
  }).then((res) => {
    if (res && res.status === 200) {
      const content = window.URL.createObjectURL(new Blob([response.data]));
      const a = document.createElement('a') // 创建a标签
      a.href = content
      a.download = '文件名'
      document.body.appendChild(a) // 兼容火狐 
      a.click()
      document.body.removeChild(a) // 移除a标签
      window.URL.revokeObjectURL(content)  // 释放content对象
    }
  }

缺点:需要对下载链接进行请求,将下载的文件转为blob格式,所以自然少不了跨域问题,并且blob格式无法在手机端浏览器下载,所以建议和上面的配合使用,手机端用上面的url方法下载,电脑端用blob

下载文字

如果是文字的话,则无需再发送请求,可直接将文字转为blob格式

    const blob = new Blob(["Hello, world!"], {type: "text/plain;charset=utf-8"});
    // 只有上面的转为blob格式不同,下面的都是一样的
    content = window.URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.href = content
    a.download = '文件名'
    document.body.appendChild(a) // 兼容火狐 
    a.click()
    document.body.removeChild(a) // 移除a标签
    window.URL.revokeObjectURL(content)  // 释放content对象

From表单下载

      const url = '下载地址'
      const form = document.createElement('form')
      form.style.display = 'none'
      form.setAttribute('target', '_blank')
      form.setAttribute('method', 'get')
      form.setAttribute('action', url)
      // 创建一个input控件:<input type="hidden" name="请求参数名" value="请求参数值"/>
      const input = document.createElement('input')
      // 设置input属性
      input.setAttribute('type', 'hidden')
      input.setAttribute('name', '请求参数名');
      input.setAttribute('value', '请求参数值');
    
      form.appendChild(input)
      document.body.appendChild(form)
      form.submit()
      document.body.removeChild(form)

下载可预览文件时,会跳转新的界面

Iframe下载

iframe下载不会出现向a标签那样的跳转问题,但是iframe兼容性较差,反正我在测试中没成功过

const url = '下载地址';
const iframe = document.createElement('iframe');
iframe.src = url;
iframe.style.display = 'none';
iframe.onload = function() {
    document.body.removeAttribute(iframe);
}
document.body.appendChild(iframe);

Canvas下载图片

      const url = '图片下载地址'
      const a = document.createElement('a')
      a.setAttribute('download', '文件名称')
      const image = new Image()
      // 添加时间戳,防止浏览器缓存图片
      image.src = url + '?timestamp=' + new Date().getTime()
      // 设置 crossOrigin 属性,解决图片跨域报错(还需要在后端设置允许跨域请求,否则仍会出现跨域问题)
      image.setAttribute('crossOrigin', 'Anonymous')
      image.onload = () => {
        // 将图片转为base64
        const canvas = document.createElement('canvas')
        canvas.width = image.width
        canvas.height = image.height
        const ctx = canvas.getContext('2d')
        ctx.drawImage(image, 0, 0, image.width, image.height)
        // 获取图片后缀名
        const extension = image.src.substring(image.src.lastIndexOf('.') + 1).toLowerCase()
        // 部分图片地址可能没有后缀名,默认为png格式
        const base64Url = canvas.toDataURL('image/' + extension, 1)
        // 也可以直接写死后缀名
        // const base64Url = canvas.toDataURL("image/png")

        a.href = base64Url
        a.click()
      }

缺点:同样需要处理跨域问题

FileSaver下载文件

使用FileSaver下载文件时仍然存在跨域问题

下载:

npm install file-saver --save

# 或者:
bower install file-saver

引入:

import fileSaver from 'file-saver'

下载文字

var blob = new Blob(["Hello, world!"], {type: "text/plain;charset=utf-8"});
fileSaver.saveAs(blob, "hello world.txt");

下载图片(画布)

var canvas = document.getElementById("canvasid");
canvas.toBlob(function(blob) {
    fileSaver.saveAs(blob, "image.png");
});

下载网络资源

fileSaver.saveAs('地址', '名称')

下载文件(file)

var file = new File(["Hello, world!"], "hello world.txt", {type: "text/plain;charset=utf-8"});
fileSaver.saveAs(file);

下载文件(blob)

fileSaver.saveAs(blob, '文件名')

示例

转为blob格式的方法,上面已经写了很多个了,这里取其中一个做示范:

const blob = await fetch('下载链接').then(res => res.blob())
fileSaver.saveAs(blob, '文件名')
前端知识积累
浏览器注入外部JS文件
2024/7/21
Vue(JavaScript)下载文件方式汇总
2024/7/21
Axios携带数据发送请求及后端接收方式
2024/7/21
发表评论