zoukankan      html  css  js  c++  java
  • javascript 实现原生下载的各种情况

    还记得第一次做文档下载的时候,基于windows.open('download_url')的方式下载。在某天某月某日,有领导突然review我的代码,此种方式遭到吐槽,尴尬不已。才痛下决心决定梳理一下前台的下载功能

    windows.open缺点 1.用户交互不友好 2.对于图片类型的文件,会直接打开浏览器,而不是下载等等,自己领悟

    下方的方式很多,请根据实际业务需求动态选择

    1:一般通过a标签的方式下载,利用H5的Download属性

    代码示例如下:

    场景:适用于现代浏览器,url是下载地址,而不是文件流,常用于GET请求

     1 function downLoad(downUrl, fileName) {
     2   let a = document.createElement("a");// 创建a标签
     3   if ('download' in a) {
     4     a.download = fileName;// 设置下载文件的文件名
     5   }
     6   (document.body || document.documentElement).appendChild(a);
     7   a.href = downUrl;// downUrl为后台返回的下载地址
     8   a.target = '_parent';
     9   a.click();// 设置点击事件
    10   a.remove(); // 移除a标签
    11 }
    12 
    13 downLoad(URL, 'test.xlxs') //URL下载地址

    如果后台给的是文件流,则利于Blob对象包装一下文件流,常用于POST请求

    代码示例如下:

     1 function downLoad(content, fileName) {
     2   let a = document.createElement("a"),// 创建a标签
     3       blob = new Blob([content]);  //用Blob对象包装一下文件流
     4 
     5   if ('download' in a) {
     6     a.download = fileName;// 设置下载文件的文件名
     7   }
     8   (document.body || document.documentElement).appendChild(a);
     9   a.href = window.URL.createObjectUrl(blob);;// content为后台返回的文件流
    10   a.click();// 设置点击事件
    11   a.remove(); // 移除a标签
    12 }
    13 downLoad('我是文件流我是文件流', 'test.txt')

    如果是POST请求,可以借助axios实现,配合FileReader对象。

     1 axios.post(downloadUrl, this.searchParams, {
     2   responseType: 'blob'
     3 }).then(res => {
     4   const blob = res.data
     5   const reader = new FileReader()
     6   reader.readAsDataURL(blob)
     7   reader.onload = (e) => {
     8     const a = document.createElement('a')
     9     a.download = `表格名称.xlsx`
    10     a.href = e.target.result
    11     document.body.appendChild(a)
    12     a.click()
    13     document.body.removeChild(a)
    14   }
    15 }).catch(err => {
    16   console.log(err.message)
    17 })

    2:借助Base64实现文件的下载

    对于非文本文件,也是可以借助JS下载的,比如下载图片,前端直接可以转化为base64然后下载

    直接上实例代码吧,应该都看得懂,我就不多说了,

    代码来自张鑫旭的关于下载的博文,可以直接查看

     1 function download (domImg, filename) {
     2   // 创建隐藏的可下载链接
     3   let eleLink = document.createElement('a');
     4   eleLink.download = filename;
     5   eleLink.style.display = 'none';
     6   // 图片转base64地址
     7   let canvas = document.createElement('canvas');
     8   let context = canvas.getContext('2d');
     9   let width = domImg.naturalWidth;
    10   let height = domImg.naturalHeight;
    11   context.drawImage(domImg, 0, 0);
    12   // 如果是PNG图片,则canvas.toDataURL('image/png')
    13   eleLink.href = canvas.toDataURL('image/jpeg');
    14   // 触发点击
    15   document.body.appendChild(eleLink);
    16   eleLink.click();
    17   // 然后移除
    18   document.body.removeChild(eleLink);
    19 };

     3:通过formData标签的方式下载,这是平安易建产品所使用的下载方式,兼容低版本浏览器

    直接上代码,因为涉及到加签验签和平安的实际业务,所以看不懂就不用看了,直接上代码,用于自己以后参考

     1 function downfile(file) {
     2   if (file == undefined || file == null) {
     3     return;
     4   }
     5   const nonce = Math.floor(Math.random() * (Math.floor(100) - Math.ceil(1))) + Math.ceil(1);
     6   const timestamp = parseInt(Date.now() / 1000);
     7   const searchParams = {
     8     storageKey: file.storageKey, // 文件系统文件key
     9     tokenType: 2, // 申请token的类型,1:上传,2:下载,5:预览
    10     nonce,
    11     timestamp,
    12     alg: 'MD5',
    13   };
    14   axios({ url: '/docs/api/file/token/applyToken', method: 'get', params: searchParams })
    15     .then(res => {
    16       if (!res.status === 200 || !res.data) {
    17         return;
    18       } if (!res.data.success) {
    19         const msg = res.data.msg && res.data.msg.length > 0 ? res.data.msg : '下载失败!';
    20         message.error(msg);
    21 
    22       } else {
    23         res = res.data || {};
    24         let content = {};
    25         if (res.data.contentList && res.data.contentList.length > 0) {
    26           content = res.data.contentList[0];
    27         }
    28         return {
    29           nodeUrl: content.nodeUrl,
    30           token: content.token
    31         }
    32       }
    33     }).then(({ nodeUrl, token }) => {
    34       const url = `${nodeUrl}/node/download/view/${file.storageKey}`; // 文件下载路径
    35       const form = document.createElement('form');
    36       form.setAttribute("method", "get");
    37       form.setAttribute("name", "theForm");
    38       form.setAttribute("target", "_self");
    39       form.setAttribute('style', 'display:none');
    40       form.setAttribute("action", url);
    41       document.body.appendChild(form);
    42 
    43       const newinput_fileToken = document.createElement('input');
    44       newinput_fileToken.setAttribute('type', 'hidden');
    45       newinput_fileToken.setAttribute('name', 'fileToken');
    46       newinput_fileToken.setAttribute('value', token)
    47 
    48       const newinput_fileName = document.createElement('input');
    49       newinput_fileName.setAttribute('type', 'hidden');
    50       newinput_fileName.setAttribute('name', 'fileName');
    51       newinput_fileName.setAttribute('value', file.name)
    52 
    53       form.appendChild(newinput_fileToken);
    54       form.appendChild(newinput_fileName);
    55 
    56       form.submit();
    57       document.theForm.parentNode.removeChild(form);
    58     });
    59 }

    另附折叠版的批量下载,实际上差不多一样,如果以后实际项目中遇到,可以综合在一起

     1 function batchDownfile(files, useType) {
     2   if(files == undefined || files == null || files.length == 0){
     3     return;
     4   }
     5   let applyTokenForms = [];
     6   const hasDoc = files.some(file => file.type == 1)
     7   if(hasDoc){
     8     applyTokenForms = files.map(it => ({
     9       fileId: it.id
    10     }))
    11   } else {
    12     applyTokenForms = files.map(it => ({
    13       storageKey: it.storageKey,
    14       fileName: it.name
    15     }))
    16   }
    17   const param = hasDoc ? {
    18     useType: 11
    19   } : {}
    20   if(useType){
    21     param.useType = useType
    22   }
    23   const nonce = Math.floor(Math.random()*(Math.floor(100)-Math.ceil(1)))+Math.ceil(1);
    24   const timestamp = parseInt(Date.now()/1000);
    25   const searchParams = {
    26     ...param,
    27     applyTokenForms,
    28     tokenType: 4, // 申请token的类型,1:上传,2:下载,4, 批量下载, 5:预览
    29     nonce,
    30     timestamp,
    31     alg:'MD5',
    32   }; 
    33   const newParam =  setParamSign(JSON.parse(JSON.stringify(searchParams)));
    34   axios.post(`/docs/api/file/token/applyTokens`,parse(newParam))
    35     .then(res => {
    36       if (!res.status === 200 || !res.data){ 
    37         return; 
    38       }if(!res.data.success){
    39         const msg = res.data.msg && res.data.msg.length > 0 ? res.data.msg : '下载失败!';
    40         message.error(msg);  
    41               
    42       }else{
    43         res = res.data || {};
    44         let fileList = [];
    45         let nodeUrl = '';
    46         let zipName = '';
    47         if(res.data && res.data.length > 0){
    48           fileList = res.data.map(it => {
    49             let file = {};
    50             if(it.contentList && it.contentList.length > 0){
    51               if(zipName == ''){
    52                 zipName = `${files.length > 1 ? `${files[0].name  }等` : (files.length == 1 ? files[0].name : '未知')  }.zip`
    53               }
    54               const firstContent = it.contentList[0];
    55               file = {
    56                 fileId: firstContent.fileId,
    57                 fileName: firstContent.filePath,
    58                 token: firstContent.token
    59               }
    60               if(nodeUrl == ''){
    61                 nodeUrl = firstContent.nodeUrl
    62               }
    63             }
    64             return file;
    65           })
    66         }
    67         return {
    68           fileList,
    69           nodeUrl,
    70           zipName
    71         }
    72       }
    73     }).then(({fileList, nodeUrl, zipName}) => {
    74       const url = `${nodeUrl  }/node/zip/json`; // 文件下载路径
    75       const form = document.createElement('form');
    76       form.setAttribute("method", "post"); 
    77       form.setAttribute("name", "theForm");
    78       form.setAttribute("target", "_self");
    79       form.setAttribute('style', 'display:none');
    80       form.setAttribute("action", url); 
    81       document.body.appendChild(form);
    82 
    83       const newinput = document.createElement('input');
    84       newinput.setAttribute('type','hidden');
    85       newinput.setAttribute('name','strFileList');
    86       newinput.setAttribute('value',JSON.stringify(fileList))
    87 
    88       const newinput2 = document.createElement('input');
    89       newinput2.setAttribute('type','hidden');
    90       newinput2.setAttribute('name','zipName');
    91       newinput2.setAttribute('value', zipName)
    92 
    93       form.appendChild(newinput);
    94       form.appendChild(newinput2);
    95       form.submit();
    96       document.theForm.parentNode.removeChild(form);
    97     });
    98 }
    View Code

    暂时结束,以后补充,还可以采用FormData对象实现下载,和$('Form')差不多,这里就不一一列举了

  • 相关阅读:
    自动化测试成功11333
    自动化测试成功11222
    自动化测试成功1111
    自动化测试成功112
    自动化测试成功18
    自动化测试成功1
    自动化测试成功
    富文本测试
    关于VMware虚拟机磁盘收缩的几种方法
    8个让你更有效率的简单方法
  • 原文地址:https://www.cnblogs.com/ajaxkong/p/11686041.html
Copyright © 2011-2022 走看看