使用 <a> 标签让图片直接下载而不是在新标签页中打开

引言

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-Typeimage/*,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 ,感谢您的关注~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值