mySkey - 前端下载文件的几种方式

盘点几种前端下载文件的方式,location.href,window.open,iframe,form表单,二进制流,a标签超链接。分别总结下不同的特点及优势。

location.href

location.href直接指向一个文件的话,浏览器会下载该文件。
对于单文件下载没有什么问题,但是如果下载多文件,点击过快就会重置掉前面的请求。

  1. const download = (url) => {
  2. window.location.href = url;
  3. }

我选了这个

这个最简洁,为了避免重置,加了延时。

window.open

window.open可以打开一个新窗口,虽然能通过这种方式下载文件,但是新的窗口不会关闭,明显体验上不好:

  1. const download = (url) => {
  2. window.open(url);
  3. }

iframe

iframe也可以向服务器发请求的,并且不会因为多次点击而重置之前的链接,可用于多文件下载:

  1. const download = (url) => {
  2. const iframe = document.createElement("iframe");
  3. iframe.style.display = "none"; // 防止影响页面
  4. iframe.style.height = 0; // 防止影响页面
  5. iframe.src = url;
  6. document.body.appendChild(iframe); // 这一行必须,iframe挂在到dom树上才会发请求
  7. // 5分钟之后删除(onload方法对于下载链接不起作用,就先抠脚一下吧)
  8. setTimeout(()=>{
  9. iframe.remove();
  10. }, 5 * 60 * 1000);
  11. }

form表单

利用form表单提交能发起浏览器请求,并且也可以作为多文件下载来使用:

  1. const download = (url) => {
  2. var params = {// 参数
  3. idxx,
  4. name:xx
  5. };
  6. var form = document.createElement('form')
  7. form.id = 'form'
  8. form.name = 'form'
  9. document.body.appendChild (form)
  10. for (var obj in params) {
  11. if (params.hasOwnProperty(obj)) {
  12. var input = document.createElement('input')
  13. input.tpye='hidden'
  14. input.name = obj;
  15. input.value = params[obj]
  16. form.appendChild(input)
  17. }
  18. }
  19. form.method = "GET" //请求方式
  20. form.action = url
  21. form.submit()
  22. document.body.removeChild(form)
  23. }

二进制流

有时候后端返回是一个Blob的文件流形式,那么前端需要自己将文件流转成链接,然后下载:

  1. const download = (content, fileName) => {
  2. const blob = new Blob([content]);
  3. const a = document.createElement("a");
  4. const url = window.URL.createObjectURL(blob);
  5. const filename = fileName;
  6. a.href = url;
  7. a.download = filename;
  8. a.click();
  9. window.URL.revokeObjectURL(url);
  10. }

a标签

a标签及href指向的如果是一个下载链接,那么相当于下载文件,对于单文件下载还是ok的,不过快速点击几个下载按钮,有的下载会被Cancelled,这可不行:

  1. const download = (url, fileName) => {
  2. const a = document.createElement("a");
  3. a.href = url;
  4. a.download = fileName;
  5. a.click();
  6. }

form表单校验

  1. function checkFormRules(rules, d) {
  2. let result = false;
  3. const ruleObj = {
  4. required: (_, val) => !val,
  5. len: (base, val) => base != val.length,
  6. min: (base, val) => base > val.length,
  7. max: (base, val) => base < val.length,
  8. pattern: (base, val) => !base.test(val),
  9. }
  10. outer:
  11. for (let i in rules) {
  12. inter:
  13. for (let j in rules[i]) {
  14. const item = rules[i][j]
  15. const itemKeys = Object.keys(item).filter(key => Object.keys(ruleObj).includes(key))
  16. if (itemKeys.filter(key => ruleObj[key](item[key], d[i])).length>0) {
  17. result = item['message']
  18. break outer;
  19. }
  20. }
  21. }
  22. return result
  23. }

lodash封装

  1. const lodash = {}
  2. const arrayExtend = {}
  3. const stringExtend = {}
  4. const objectExtend = {
  5. get(obj, key, defaultValue) {
  6. let result = obj;
  7. for (let k of key.split('.')) {
  8. if (result[k]) {
  9. result = result[k]
  10. } else {
  11. result = false
  12. break;
  13. }
  14. }
  15. return result || defaultValue
  16. }
  17. }
  18. const functionExtend = {}
  19. const mathExtend = {}
  20. const numberExtend = {}
  21. const extendType = [
  22. {
  23. type: Array,
  24. children: [
  25. 'join',
  26. 'concat'
  27. ],
  28. extendFuns: arrayExtend
  29. },
  30. {
  31. type: String,
  32. children: [
  33. 'split',
  34. 'trim'
  35. ],
  36. extendFuns: stringExtend
  37. },
  38. {
  39. type: Object,
  40. children: [
  41. 'assign'
  42. ],
  43. extendFuns: objectExtend
  44. },
  45. {
  46. type: Function,
  47. children: [
  48. 'bind'
  49. ],
  50. extendFuns: functionExtend
  51. },
  52. {
  53. type: Math,
  54. children: [
  55. 'min'
  56. ],
  57. extendFuns: mathExtend
  58. },
  59. {
  60. type: Number,
  61. children: [
  62. 'toFixed'
  63. ],
  64. extendFuns: numberExtend
  65. },
  66. ]
  67. extendType.forEach(item => {
  68. const { children = [], extendFuns = {} } = item
  69. for (let key of children) {
  70. lodash[key] = (obj, ...args) => item.type.prototype[key].call(obj, ...args)
  71. }
  72. for (let key in extendFuns) {
  73. lodash[key] = extendFuns[key]
  74. }
  75. })
  76. console.log(lodash.get({user:{name: '55'}}, 'user.name'))
  77. console.log(lodash.join([1, 2, 3], '-'))