解决因跨域导致使用a标签下载文件download属性失效无法自定义命名的问题

问题背景:

在使用a标签下载文件时,download属性可以更改下载的文件名。

// 下载a.exe,并采用默认命名
<a href="/images/a.exe" download>点击下载</a>


// 将a.exe改名为b.exe下载
<a href="/images/a.exe" download="b">点击下载</a>

但是当a标签的下载链接跨域时,download属性将不会生效,原因是浏览器无法获取到文件,不能对他进行更改。

在这种情况下如果你是下载浏览器无法解析的文件,例如.exe,.xlsx..那么浏览器也会自动下载,但是如果你使用浏览器可以解析的文件,比如.txt,.png....浏览器就会采取预览模式,无法直接下载。

// 无法正常下载a.jpg,会直接预览
<a href="https://www.baidu.com/a.jpg" download>点击下载</a>

// 正常下载a.exe文件
<a href="https://www.baidu.com/a.exe" download>点击下载</a>

注意:

html5 新特性a标签download属性只支持谷歌和火狐
在谷歌和火狐浏览器a标签download属性修改文件名失效的原因:不同源,访问的域名和href的域名要一致。

a标签属性文档<a>:锚元素 - HTML(超文本标记语言) | MDN

什么是同源url:

 解决方法:

使用Blob实现文件下载,先把文件以bobl的形式下载到当前页面,再创建a标签。

// 下载url(解决跨域a.download不生效问题)
      downloadFile(url, fileName) {
        const x = new XMLHttpRequest()
        x.open("GET", url, true)
        x.responseType = 'blob'
        x.onload = function(e) {
          const url = window.URL.createObjectURL(x.response)
          const a = document.createElement('a')
          a.href = url
          a.target = '_blank'
          a.download = fileName
          a.click()
          a.remove()
        }
        x.send()
      },

 使用方法:

      <el-link
        :disabled="validateNull(fileUrl)"
        :type="validateNull(fileUrl) ? 'info' : 'primary'"
        :underline="true"
        style="font-size:14px;"
        @click="downloadFile(fileUrl, fileName)"
      >
        {{ fileName|| '-' }}
      </el-link>

这里的validateNull是校验url是否为空:

/**
 * 判断是否为空
 */
export function validatenull(val) {
  if (typeof val === 'boolean') {
    return false;
  }
  if (typeof val === 'number') {
    return false;
  }
  if (val instanceof Array) {
    if (val.length===0) return true;
  } else if (val instanceof Object) {
    if (JSON.stringify(val) === '{}') return true;
  } else {
    if (val==='null' || val===null || val==='undefined' || val===undefined || val==='') return true;
    return false;
  }
  return false;
}

这个下载方法有个需要注意的问题就是,当自定义的fileName内存在小数点时(如 fileName = '附件v1.2.zip'),如果没有在fileName后面加上后缀名(fileName = '附件v1.2'),会导致下载时自动以第一个小数点后面的为文件后缀名(.2),所以这时还要加一个方法判断文件的后缀名,将后缀名加到自定义的文件名后面:

function getFileTypeByPath(pathUrl) {
  let index = pathUrl.lastIndexOf(".") // lastIndexOf(".")  找到最后一个  .  的位置
  let fileType = pathUrl.substr(index + 1) // substr() 截取剩余的字符,即文件后缀名 doc 、jpg 、 xlsx 等
  return fileType
}

此时我们传入的fileName为:

const suffix = this.getFileTypeByPath(fileUrl)
this.suffix = `.${suffix}`
const fileName = '附件v1.2'
this.fileName = `${fileName}${this.suffix}`

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值