引言
当 a
标签中添加了 download
属性,想要实现下载图片时,点击 a
链接,没有进行下载,而是在当前页面打开了图片。
原因
使用 a
标签的 download
属性进行下载操作时,如果下载的是图片视频类的,则只能下载 同源文件,非同源的文件 浏览器会自动打开浏览而非下载,那么非同源的该如何操作才能下载呢?
下面给出几种解决方案。
解决方案
- 1.通过 canvas 方式 保存图片
// 只支持图片类型下载
function downloadIamge(fileUrl: string, fileName: string) {
// 新建图片对象
const image = new Image();
// 解决跨域 Canvas 污染问题
image.setAttribute('crossOrigin', 'anonymous');
// 图片加载
image.onload = function () {
// 新建 canvas标签
const canvas = document.createElement('canvas');
// 设置 canvas宽高
canvas.width = image.width;
canvas.height = image.height;
// 添加 canvas画笔
const context: any = canvas.getContext('2d');
// 绘制图片
context.drawImage(image, 0, 0, image.width, image.height);
// 得到图片的 base64 编码
const url = canvas.toDataURL('image/png');
// 新建 a标签
const a = document.createElement('a');
// 新建点击事件
const event = new MouseEvent('click');
// 设置下载文件名
a.download = fileName || 'photo';
// 将图片的 base64 编码,设置为 a标签的地址
a.href = url;
// 触发点击事件
a.dispatchEvent(event);
};
// 将图片地址 设置为 传入的参数 fileUrl
image.src = fileUrl;
}
- 2.我们自己请求获取文件流,然后把内容传给浏览器。
// 下载任何形式
async function downloadFile(fileUrl: string, fileName: string) {
// 使用axios获取网络图片数据
const response = await request.get(fileUrl, {
responseType: 'arraybuffer',
});
const imageData = response.data;
// 将图片数据转换为Blob对象
const blob = new Blob([imageData], {
type: response.headers['content-type'],
});
// 1.将blob转成本地预览地址
// const blobUrl = URL.createObjectURL(blob);
// 2.将文件对象转成本地预览地址 创建一个新的File对象
const file = new File([blob], fileName, { type: blob.type });
const blobUrl = URL.createObjectURL(file);
const link = document.createElement('a');
link.setAttribute('href', blobUrl);
link.setAttribute('download', fileName);
link.setAttribute('target', '_blank');
document.body.appendChild(link);
link.click();
document.body.removeChild(link); // 可选
URL.revokeObjectURL(blobUrl);
}
- 3.在
url
最后加上“response-content-type=application/octet-stream”
即可!至于为什么加这个参数能下载下来,是因为如果你的图片请求返回的响应的Content-Type
是image/*,audio/*
等浏览器可以识别打开的文件,就不会去执行下载事件
如果你想要下载,不想要预览,就加上上述添加的参数,它指的是任意类型的二进制流数据
,浏览器无法识别打开流数据,就会去下载。
// 利用设置content-type下载
function downloadFileByContentType(fileUrl: string, fileName: string) {
const link = document.createElement('a');
link.href = `${fileUrl}?response-content-type=application/octet-stream`;
link.setAttribute('download', fileName); // 设置下载文件名
document.body.appendChild(link);
link.click();
// 清理
document.body.removeChild(link); // 可选
window.URL.revokeObjectURL(fileUrl); // 释放 URL 对象
}
写在最后
文件或图片下载,归根到底就是让浏览器根据URL地址和相关的响应头来对资源进行保存。
喜欢的话帮忙点个赞 + 关注吧,将持续更新 JavaScript
相关的文章,还可以关注我的公众号 梁三石FE
,感谢您的关注~