Vue下载文件的四种方式

Daotin 于 2020-04-28 发布 编辑
  1. 1、a标签url下载
  2. 1.1、a标签download属性下载
  3. 2、把地址传入浏览器地址中触发下载
  4. 2.1、通过js构建a标签进行下载
  5. 3、form表单提交下载
  6. 其他下载方式
  7. 下载后缀为.lnk遇到的怪事
  8. Q&A

平时我们在前端项目中都是怎么下载资源的?比如一个word文档等,这里简单总结了4种方式。

1、a标签url下载

exportUrl 是下载地址,点击之后直接在当前界面下载文件

<a :href="exportUrl" class="g-button simple">导出</a> 

1.1、a标签download属性下载

a标签的download是HTML5标准新增的属性,作用是指示浏览器下载URL而不是导航到URL,因此将提示用户将其保存为本地文件。

代码示例:

<a href="http://ww2.sinaimg.cn/large/4b4d632fgw1f1hhza4495j20ku0rsjxs.jpg" download>下载</a>

注意:此属性仅适用于同源 URL,跨域的资源无效。

那么如何解决跨域文件?

尽管 HTTP URL 需要位于同一源中,但是可以使用 blob: URLdata: URL ,以方便用户下载使用 JavaScript 生成的内容以解决跨域问题。

跨域资源下载:

// 下载一个文本文件
const downloadText = (text, filename = '') {
  const a = document.createElement('a')
  a.download = filename
  // 文本txt类型 
  const blob = new Blob([text], {type: 'text/plain'}) 
  // text指需要下载的文本或字符串内容
  a.href = window.URL.createObjectURL(blob) 
  // 会生成一个类似blob:http://localhost:8080/d3958f5c-0777-0845-9dcf-2cb28783acaf 这样的URL字符串
  document.body.appendChild(a)  
  a.click()
  a.remove()
}

2、把地址传入浏览器地址中触发下载

window.open(exportUrl, '_self'); // 本窗口打开下载,地址栏的地址并不会改变
window.open(exportUrl, '_blank'); // 新开窗口下载

2.1、通过js构建a标签进行下载

const link = document.createElement("a");
link.href = `${BASEURL}sftp/${row.id}/download/exec`;
link.setAttribute("download", 'test.png'); //设置下载属性 以及文件名
document.body.appendChild(link); //a标签插至页面中
link.click(); //强制触发a标签事件
document.body.removeChild(link);

3、form表单提交下载

form表单的提交本质上是发送了一次HTTP请求。

<form>元素定义了如何发送数据。它的所有属性都是为了让您配置当用户点击提交按钮时发送的请求。两个最重要的属性是actionmethod

action属性

这个属性定义了发送数据要去的位置。它的值必须是一个有效的URL。如果没有提供此属性,则数据将被发送到包含这个表单的页面的URL。

method属性

该属性定义了如何发送数据。HTTP协议提供了几种执行请求的方法;HTML表单数据可以通过许多不同的方法进行数据传输,其中最常见的是GET方法和POST方法。

想要form提交数据,需要把form的action设置为接口地址,method一般设置为post,post到后台的数据为input的属性 name = keyvalue = value的形式。

  • 如果有多个key、value的值要传递,那么就设置多个input来分别储存单个的key、value;
  • 如果请求的接口可以不需要参数,那么input还是必须要一个,如果不要得话会引起接口报错。
<form action="http://xxx.com" method="post">
  <div>
    <label for="say">What greeting do you want to say?</label>
    <input name="say" id="say" value="Hi">
  </div>
  <div>
    <label for="to">Who do you want to say it to?</label>
    <input name="to" id="to" value="Mom">
  </div>
  <div>
    <button>Send my greetings</button>
  </div>
</form>

发送的表单数据为:

POST / HTTP/2.0
Host: foo.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 13

say=Hi&to=Mom

下面是封装的一个jQuery插件,使用form的形式发起http请求:

$.download = function (url, params, method) {
  if (url && params) {
    var inputs = '', input, form = $('<form />').attr("action", url).attr("method", (method || "post"));
    $.each(params, function (k, v) {
      input = $("<input type='hidden' />");
      input.attr("name", k).attr("value", v);
      form.append(input);
    });
    form.appendTo('body').submit().remove();
  }
};

使用方法:

var url = "/app/lottery/awards/export", params = { FILETYPE: "excel07", FRMID: that.FRMID };
$.download(url, params, "post");

参考链接:https://developer.mozilla.org/zh-CN/docs/Learn/Forms/Sending_and_retrieving_form_data

其他下载方式

/**
 *  下载文件。数据源是Blob对象
 */
export const downloadBlobFile = (binaryString, fileName) => {
  const blob = new Blob([binaryString], { type: "application/octet-stream" });

  const link = document.createElement("a");
  link.href = window.URL.createObjectURL(blob);
  link.download = fileName;
  link.click();
  //延时释放
  setTimeout(function () {
    window.URL.revokeObjectURL(link.href);
  }, 100);
};

/**
 *  下载文件。数据源是base64
 */
export const downloadBase64File = (data, fileName, headerType) => {
  const link = document.createElement("a");
  const header = headerMap[headerType || ""] || "";
  link.href = header + ";base64," + data;
  link.download = fileName;
  link.click();
};

/**
 *  通过文件地址下载文件
 */
export const downloadURLFile = (url, fileName) => {
  const xhr = new XMLHttpRequest();
  xhr.open("GET", url.replace(/\\/g, "/"), true);
  xhr.responseType = "blob";
  xhr.onload = () => {
    if (xhr.status === 200) {
      downloadBlobFile(xhr.response, fileName);
    }
  };
  xhr.send();
};

下载后缀为.lnk遇到的怪事

有用户反馈,下载的.lnk文件,后缀名变成了.download。

经查,只有chrome系列浏览器才有这个问题。

抓包看下请求,发现服务端在response的header里给出了正确的文件名,如:Content-Disposition: attachment; filename="xxx.lnk"

那么,这个重命名肯定是浏览器的默认行为。实际上,lnk类型的文件是一个软链,运行后会执行什么完全取决于不同的系统环境,没办法预期,Chrome认为这比较危险,就在底层强制对其重命名了。所以,这不是web应用所能决定的。

参考地址:https://imququ.com/post/download-link-file-issue-with-chrome.html

Q&A

你在前端项目中都是怎么下载文件的?欢迎再评论区和我交流吧!

(完)