Window下载

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

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

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

A标签下载

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

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

a标签download+url

1
2
3
4
5
6
7
8
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格式:

1
2
3
4
5
6
7
8
9
10
// 这里需要发送一次请求将下载地址里的文件转为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格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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格式

1
2
3
4
5
6
7
8
9
10
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表单下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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兼容性较差,反正我在测试中没成功过

1
2
3
4
5
6
7
8
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下载图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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下载文件时仍然存在跨域问题

下载:

1
2
3
4
npm install file-saver --save

# 或者:
bower install file-saver

引入:

1
import fileSaver from 'file-saver'

下载文字

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

下载图片(画布)

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

下载网络资源

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

下载文件(file)

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

下载文件(blob)

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

示例

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

1
2
const blob = await fetch('下载链接').then(res => res.blob())
fileSaver.saveAs(blob, '文件名')