前端需要下载的软件(前端教程下载)
作者:luffyZh转发链接:https://github。com/lufyzh/frontend下载-示例
前言我在自己编的一些项目中遇到的一些关于上传下载的Demo,大前端系列(就是纯前端节点完成的下载,只要数据下载工作都是前端做的),仅供大家参考,避免踩坑,即插即用,
欢迎叉和星给这个仓库投稿~ (P.S .个人觉得没写过上传下载还是挺麻烦的,而且这个基本可以覆盖大部分场景~)
在此之前,边肖还整理发表了几篇关于前端下载的高质量文章:
谈文件上传下载的前端事情【练习】
五种前端下载文件方法的比较
JavaScript实现图片合成下载。
Vue元素实现excel中信息的批量导入和导入模板的下载。
如何实现一个下载/播放进度条“案例”
了解文件上传全过程(1.8w字深度分析)“前端高级必需品”
更多关于JavaScript实践项目学习的文章,请看本文底部。有惊喜。
包括内容纯前端下载,基于A标签位置iframeFileSaver——【推荐】节点端下载先下载到本地,
再下载到浏览器直接流向浏览器下载[推荐]前端-下载-样本:https://github。com/lufyzh/frontend-下载-示例
这里怕大家看了不耐烦,放一个强烈推荐的filesaver的Demo动态图。
前面写上传下载个人觉得有点复杂,前端开发迷失了,需要处理一些额外的东西而不是直接获取数据渲染页面,所以想整理分享一下平时遇到的一些场景,大牛绕开了。
不喜勿喷~我平时接触的都是上传图片,上传安装包,下载图片,下载安装包整理数据生成excel文件下载。我还没有接触过其他类型,所以这个项目可能会有一些局限性。
我只是想给你提供一个思路或者方案。如果有其他想法,欢迎评论~
顾名思义,纯前端下载形式是纯前端实现,即不依赖任何后端。但是这种方法有一定的局限性,比如下载类型、编写方法、数据形式等。但既然不依赖后端,还是在可以接受的范围内推荐。毕竟简单~
说到基于标签的简单下载,那么这是最简单的一个。那就是基于标签下载文件的方式,真的超级简单。使用方法如下:
Href:文件的绝对/相对地址下载:文件名(可以省略,省略后浏览器会自动识别源文件名)下载jpg图片。既然这么简单,那肯定有问题。
上面这张图片是官方提供的兼容性,目前只有FireFox和Chrome支持download属性。至少这两个对于开发者来说不陌生,占有量也很大,所以也还可以吧,
但是接下来我又尝试了一下这两个浏览器的兼容性情况。
上面这张,是FireFox浏览器最新版,可以看到点击下载文件会弹出一个对话框,之后点击保存文件才可以进行下载,同时只能下载不能被浏览器打开的文件类型,
如图片、文本文件、html文件这种可以被打开的文件,是无法被下载的直接在浏览器进行预览。
上面这张,是Chrome最新版,与FireFox相同,对于图片文件和文本文件这种可以被浏览器打开的文件不会被下载,而excel和安装包这种文件是可以被直接下载的,无需进行任何二次确认操作。
那么能不能不让浏览器预览图片(或pdf或txt文件)?肯定能啊为什么呢?其实a标签的href属性还可以接受除了相对和绝对路径之外的其他形式Url,比如下面我们要用到的DataUrl和BlobUrl。
我们使用这种形式,就可以让浏览器不预览而直接下载图片了,当然了操作起来更麻烦一些了就。
DataUrl //首先,图片转base64 //./util.js //html页面,将a标签href属性动态赋值为dataUrl 下载data:Url图片. 如下图,
可以看到不再是预览文件,而是直接下载文件了。这里面有一些坑,比如canvas.toDataUrl的一些问题以及解决办法,我就不多说了,大家自己去看看。
方法上面一样//第二步:将base64转换成blob数据//DataUrl 转Blob数据 function dataUrl2Blob(dataUrl) { var arr=dataUrl.split(','), mime=arr[0].match(/:(.* );/)[1], bStr=atob(arr[1]), n=bStr.length, unit8Array=new Uint8Array(n); while (n--) { unit8Array[n]=bStr.charCodeAt(n); } return new Blob([unit8Array], { type: mime }); } //第三步: 将blob数据转换成BlobUrl URL.createObjectURL(imageBlobData); //完整代码 下载blobUrl图片 . const image2=new Image(); image2.setAttribute('crossOrigin','Anonymous'); image2.src='./files/test-download.png' + ' ' + new Date().getTime(); image2.onload=function() { const imageDataUrl=image2base64(image2); const imageBlobData=dataUrl2Blob(imageDataUrl); const downloadDataUrlDom=document.getElementById('downloadBlobUrl'); downloadDataUrlDom.setAttribute('href', URL.createObjectURL(imageBlobData)); downloadDataUrlDom.setAttribute('download', 'download-data-url.png'); downloadDataUrlDom.addEventListener('click', ()={ console.log('下载文件'); }); }【总结】: Chrome在兼容性上更胜一筹,
【建议】: 如果下载的需求是特殊文件类型,如安装包,excel文件,并且可以存放在CDN又一个可访问的url链接。那么这种方式非常完美,当然,如果你可以接受上面所说的兼容性问题。
同时如果你采用dataUrl或者blobUrl的时候,由于存在很多问题,比如cors之类的事情,建议可以使用这种方法,但是需要配合后端,也就是后端帮你转换好,你直接拿转换好的url来下载就行了。
location.href 和iframe下载上面这两种非常好理解,就是在另一个窗口或者当前地址栏地址指向下载链接,下载链接要求是dataUrl或者blobUrl。只不过,iframe是更高级一些,
也就是可以帮助我们做到无闪下载,作为开发者大家应该都懂,我就不多BB了。
从上面这个动图,可以看出来,这个方法其实还不如标签下载,为什么这么说呢,会因为a标签方法虽然会预览浏览器可以预览的文件,但是如果进行适当转化,还是能进行下载的。
但是location这种方法无论是dataUrl还是blobUrl,只要是图片、文本文件以及pdf等所有浏览器可以打开的文件,都会直接给你预览,只能下载那些浏览器不支持预览的那些文件。
所以Just so so了。
iframe封装无闪现下载方法本质很简单,就是不让当前浏览器窗口执行下载操作,而是另开一个iframe进行文件的下载。但是这个iframe是用户不可见的这里需要注意,如果是纯前端,
建议不要进行图片等浏览器可打开的文件下载,因为隐藏iframe里打开你也看不到,也就是他的问题还是上面那些。可以进行excel、zip以及各种资源文件的下载。
//无闪现下载excelfunction download(url) { const iframe=document.createElement('iframe'); iframe.style.display='none'; function iframeLoad() { console.log('iframe onload'); const win=iframe.contentWindow; const doc=win.document; if (win.location.href===url) { if (doc.body.childNodes.length 0) { //response is error } iframe.parentNode.removeChild(iframe); } } if ('onload' in iframe) { iframe.onload=iframeLoad; } else if (iframe.attachEvent) { iframe.attachEvent('onload', iframeLoad); } else { iframe.onreadystatechange=function onreadystatechange() { if (iframe.readyState==='complete') { iframeLoad; } }; } iframe.src=''; document.body.appendChild(iframe); setTimeout(function loadUrl() { iframe.contentWindow.location.href=url; }, 50);}如果你在项目里需要进行无闪现下载,
使用FileSaver强大的前端下载插件- 【强烈推荐】FileSaver的下载方式完全是前端(Client-Side)的下载方式,它是基于Blob进行下载的,当然因为是基于前端下载,
所以浏览器下载会有一定的限制,也就是Blob数据的大小不能过大,看看官网给的相关参数:
可以看到,基本对于支持的浏览器来说,大小可以达到500MB+,应该已经可以满足大部分需求了。如果文件确实很大,官网给出了替代方案StreamSaver,没去研究过这个,不过作者既然推荐可能也很好,
感兴趣的可以去看看。
前面讲到了,FileSaver是基于Blob的,其实并不准确,可以看一下官网:
其实它支持Blob、File和Url进行下载,但是如果基于url了我也没必要用FileSaver了,那个标签也挺好的是不?然后基于File一般都是特定场景,比如上传的时候,
才会用到FileReader之类的API,说实话我也没怎么用过,都是封装的,所以这里也不做介绍。开头也说过了,希望小伙伴可以给这个仓库添加东西啊,可以增加自己的下载Demo到这里,非常欢迎
所以我这篇文章讨论的下载,就是基于Blob。首要工作就是将文件转换成Blob数据。下面几个例子都是这样:
FileSaver ---- 下载canvas依赖- canvas-to-blob这个Demo简单点的话其实可以直接用canvas画一个image在页面上,然后再进行下载,
但是那样还不如直接下载图片了,所以麻烦一些,写一个canvas白板,然后下载我们自己绘制的内容并且起名字进行下载。
//生成下载的文件名 function generateFilename(id, mime) { const filename=document.getElementById(id).value || document.getElementById(id).placeholder; return filename + mime; } const canvasDownloadDom=document.getElementById('download-canvas'); canvasDownloadDom.addEventListener('click', ()={ const canvas=document.getElementById('canvas'); const filename=generateFilename('canvasName', '.png'); if (canvas.toBlob) { //调用方法将canvas转换成blob数据 canvas.toBlob( function (blob) { //调用FileSaver方法下载 saveAs(blob, filename); }, 'image/png' ); } });代码非常简单,
FileSaver ---- 直接下载图片直接下载图片就是将图片转换成Blob数据,然后进行下载。
//FileSaver 下载文件 const image=new Image(); image.setAttribute('crossOrigin','Anonymous'); image.src='./files/test-download.png' + ' ' + new Date().getTime(); image.onload=function() { const imageDataUrl=image2base64(image); const imageBlobData=dataUrl2Blob(imageDataUrl); const downloadImageDom=document.getElementById('download-image'); downloadImageDom.addEventListener('click', ()={ saveAs(imageBlobData, 'test-download.png'); }); }这代码就更简单了,
FileSaver ---- 下载文本文件下载文本文件就更容易了,因为JavaScript支持直接将字符串构造成Blob对象。
const textBlob=new Blob(['your target string'], {type: 'text/plain;charset=utf-8'});
下载下来的txt文件长这样:
//FileSaver 下载文本文件 const txtDownloadDom=document.getElementById('download-txt'); txtDownloadDom.addEventListener('click', ()={ const textarea=document.getElementById('textarea'); const filename=generateFilename('textareaName', '.txt'); const textBlob=new Blob([textarea.value], {type: 'text/plain;charset=utf-8'}); saveAs(textBlob, filename); });FileSaver ---- 下载Excel文件(搭配js-xlsx)前面的都相对简单一些,
下载下来的文件长这样:
//下载excel文件 const excelDownloadDom=document.getElementById('download-excel'); excelDownloadDom.addEventListener('click', ()={ //找到table节点调用方法转化数据 const wb=XLSX.utils.table_to_book(document.querySelector('#table-excel')); //生成excel数据 const wbout=XLSX.write(wb, { bookType: 'xlsx', bookSST: true, type: 'array' }); try { //下载excel文件 saveAs(new Blob([wbout], { type: 'application/octet-stream' }), 'table-excel.xlsx'); } catch (e) { if (typeof console !=='undefined') console.log(e, wbout) } });这里面我只是介绍如何用FileSaver在前端下载excel文件,
node端配合下载(大前端)带后端支持的下载就要轻松很多了,为什么呢,因为上面所有纯前端下载都可以与后端进行配合使用,也就是后端生成对应的下载链接下载数据返回给前端,
前端根据设计方案按需使用上面几种方式下载,肯定能下载成功。那么node端配合下载肯定是要下载点不一样的东西了——那就是文件流。
有很多场景,那就是大文件不是存在于CDN,而是以文件流的形式存放在内存。那么就没有对应的下载链接,下载对应文件的时候,后端返回的就是文件流。而node里为我们提供Stream支持各种流操纵。
所以我们可以在node端直接进行文件的下载。
先下载到本地再从浏览器下载fs下载Excel 下载下来的Excel文件://第一步:构造数据const data=[ [1, 2, 3], [true, false, null, 'sheetjs'], ['foo', 'bar', new Date('2014-02-19T14:30Z'), '0.3'], ['baz', null, 'qux'],];//第二步:生成excel的Buffer数据const buffer=xlsx.build([{ name: 'mySheetName', data }]);//第三步:写文件到本地const tmpExcel=`filename.xlsx`;fs.writeFileSync( tmpExcel, buffer, { encoding: 'utf8', }, err={ if (err) throw new Error(err); },);//第四步:从本地读取文件下载到浏览器res.setHeader('Content-disposition', `attachment; filename='${tmpExcel}'`);res.setHeader('Content-Type', 'application/octet-stream');//pipe generated file to the responsefs.createReadStream(tmpExcel).pipe(res);//下载完成后删除文件fs.unlinkSync(tmpExcel);下载excel在node端我使用的不是js-xlsx而是node-xlsx,
fs下载文件这里场景不是很容易描述,因为Demo我都是将文件放到本地目录的,所以我读取本地文件再下载到本地再下载到浏览器,我这不是有病吗。一般场景是文件以文件流的形式存在内存里,
然后我们通过接口下载到本地再从本地下载到浏览器。或者是上传文件保存到本地,然后再从本地进行相关操作,这里就不写示例代码了。
node端直接流向浏览器下载【推荐】node端,我使用的是express框架(其他的框架也都一样),如果你是文件流直接过来的,那么直接调用res.attachment()下载文件流,
如果是文件path,那么可以直接res.download(filepath)。具体见demo
直接下载Excel上面过程其实多经历了一步,为什么呢?因为拿到buffer之后我们其实就可以直接将buffer流向浏览器下载了这里我用的是Express框架,
直接使用res.attachment()方法就可以了。
下载下来的文件
与上面一模一样我就不展示了。
按照我的理解,第二种明显要比第一种好很多为什么还要列出第一种呢?我个人觉得,第一种虽然一定会牺牲一定的性能,但是先下载到本地就可以对文件进行一些校验,比如文件是否完整,文件名之类的是否合法,
还有些时候的场景可能。毕竟不是所有的下载场景都像Demo这样简单。存在即合理,所以还是都罗列出来。
//第一步:构造数据const data=[ [1, 2, 3], [true, false, null, 'sheetjs'], ['foo', 'bar', new Date('2014-02-19T14:30Z'), '0.3'], ['baz', null, 'qux'],];//第二步:生成bufferconst buffer=xlsx.build([{ name: 'mySheetName', data }]);//第三步:直接下载res.status(200) .attachment('bufferExcel.xlsx') .send(buffer);//上面下载代码等同于下面这段代码(nodejs原生代码)res.setHeader('Content-disposition', `attachment; filename='${tmpExcel}'`);res.setHeader('Content-Type', 'application/octet-stream');res.end(buffer);直接下载文件流这里我把文件安装包放在本地了,
已知文件路径直接下载try { const packagePath='static/download/iTerm2-3_2_5.zip'; res.download(path.join(rootDir, packagePath));} catch (e) { console.error(e);}//第二种,
//不加这一行下载下来的文件没有后缀res.setHeader('Content-disposition', 'attachment; filename=node-v8.14.0-linux-x64.tar.gz');request('https://npm.taobao.org/mirrors/node/v8.14.0/node-v8.14.0-linux-x64.tar.gz') .pipe(res);这里我为了省时间,
地址:https://github.com/luffyZh/next-antd-scaffold
总结看到这里无论怎么样都十分感谢了,总结的不怎么样,可以理解为自我总结文章吧。如果对大家能有那么一点点启发那就更好了。最后如果有兴趣或者有疑问,可以留言或者直接去仓库里提
github:https://github.com/luffyZh/frontend-download-sample
推荐JavaScript学习