前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的中心思想,我们开课啦(每周四)。
这两天,碰到了不止一次前端下载的的问题。其实之前我写过一篇文章 download使用浅析,主要依靠 download
属性来实现浏览器端下载,因为是走浏览器的下载,所以没有进度条。今天我们就来说说我的解决方案。
- sf 的一个问题,需要显示进度条。答案地址,问题地址
- 一个朋友的问题,下载的文件需要 headers 验证,无奈只能 ajax 拿数据,但是拉回来的还是字符串,需要自己处理。
- 一个朋友的问题,监测下载进度。
今天我们要讲什么?
- 如何使用 download 属性,下载文件。
这节主要是讲如何使用,以及前端下载的核心操作。 - 下载文件,并显示进度条。
这节是正常操作,如果你只为了解原理,看到这里就够了 - 其他数据类型如何互相转换
这节就不一样了。因为之前的 api 是使用 blob 实现,但是 ajax 传回来的数据有好多种类型,我们如何将他们相互转换?
如何使用 download 属性,下载文件。
download使用浅析 这一文中已经介绍了,可以去看看。我这里简单说一下。<a>
标签如果设置了 download
属性,他就会去下载这个地址。测试地址-原生 download 属性测试。
下载文件,并显示进度条
下载文件上面已经实现了,那我们先说说如何显示进度条。
显示进度条
其实浏览器也是有进度条的,但是咱们拿不到。那我们就来模拟一下载,然后显示进度条。
-
ajax
实现下载进度条,测试地址-显示进度条xhr = new XMLHttpRequest(); xhr.open('get', file1.url); xhr.onprogress = (e)=>console.log(e)//e 就是一个 ProgressEvent 对象,其中 loaded 是已下载的, total 是总大小。 xhr.send()
-
fetch
实现下载进度条,测试地址-fetch显示进度条并下载fetch
的实现上来说有一些功能是没有的,比如abort
、进度等。那我们就需要去通过一些别的手段来模拟实现。
实现代码如下,我们操作成读流,然后统计长度。
下载文件
进度条已经显示好了,那我们可以下载文件了。首先我们要分几种情况
- 缓存下载(一个资源如果已经下载完了,再次去访问)
-
本地下载(资源已经在浏览器中)
-
blob
url 下载 如这种地址blob:https://www.lilnong.top/deb4c297-821c-4545-9b23-0fbdd76890c7
-
base64
url 下载 如这种地址data:application/octet-stream;base64,aGVsbG8gbGlub25n
blob = new Blob(['hello linong']) freader = new FileReader() freader.readAsDataURL(blob)//将 blob 读成 dataurl freader.onload=e=>console.log(freader.result)// 异步的,所以需要回调里面拿
-
- 无缓存下载(资源没在本地,也没有缓存)
情况就是上面几种,那我们要做的其实就是统一一下流程
- ajax 拉取数据(显示进度条)
-
缓存了数据,然后下载缓存(因为是缓存,所以秒下)
- 浏览器缓存
我比较推荐用这个,因为其他的方案都有大小或者兼容上的问题。但是这个缓存需要服务器设置需要走缓存。 -
bloburl
本地缓存下载
这个方案在移动端异常,pc端正常,感兴趣的小伙伴可以自己实现一下,毕竟学了这么多,得用起来才能变成自己的 -
dataurl
本地缓存下载
这个方案的支持会比bloburl
好一点,但是只适用于小文件。
- 浏览器缓存
实现前端下载文件并显示进度条
我们让 ajax
直接返回 blob
。然后构建 bloburl
用于下载。
downloadFile2 = (url)=>{
var xhr = new XMLHttpRequest();
xhr.open('get', url);
xhr.responseType='blob';//这是精髓
xhr.onprogress = onprogress2;//下载进度
// .upload.onprogress 这个是上传的时候的进度
xhr.onreadystatechange = ()=>{
if(xhr.readyState == 4 && xhr.status == 200){
nativeDownload(URL.createObjectURL(xhr.response))
}
}
xhr.send()
}
其他类型转换为 blob
如果是一些封装过的 ajax
,没办法使用 xhr.responseType='blob'
之类的,返回回来是字符串。那我们需要怎么出转换呢?
blob
to *
blob
需要配合 FileReader
来读取
-
blob
toarrayBuffer
(readAsArrayBuffer
)
通用的、固定长度的原始二进制数据缓冲区var fileReader = new FileReader(); fileReader.readAsArrayBuffer(xhr.response);//xhr.reponse 是 blob 类型 fileReader.onload = e=>console.log(fileReader.result);
-
blob
toDataURL
(readAsDataURL
)Base64 是一组相似的二进制到文本(binary-to-text)的编码规则,使得二进制数据在解释成 radix-64 的表现形式后能够用 ASCII 字符串的格式表示出来。Base64 这个词出自一种 MIME 数据传输编码。 --MDN
-
blob
toText
(readAsText
)
以字符串表示所读取的文件内容
-
blob
toBinaryString
(readAsBinaryString
)
文件的原始二进制数据
*
to blob
-
arrayBuffer
toblob
new Blob([arrayBuffer], {type: 'image/jpeg'})
-
base64
toblob
(new Uint8Array(Array.from(atob(base64url.split(',')[1])).map(v=>v.charCodeAt()))).buffer //base64url.split(',')[1] //截取不要 data:images/jpeg;base64, 这串 //atob //转换成 BinaryString //Array.from //转换成数组 //map(v=>v.charCodeAt()) //转换成对应的 ascii 码 //Uint8Array 转换成 Uint8Array 然后输出 buffer
-
BinaryString
toblob
方案同上,因为上面的也是转换成了BinaryString
-
Text
toblob
ajax
默认就是Text
类型的返回值。这个我觉得是编码类型的转换,比如utf-8
toascii
,目前我还没找到好的实现方法。
总结
之前就写过一篇AJAX 的进阶使用(Blob、ArrayBuffer、FormData、Document、JSON、Text),里面讲了这些支持的类型。
base64转换上传,也写过这样的。
前端目前需要操作的东西越来越多了。
在最上面那个问答里,有个库去实现 download 操作。实现原理可以自己去看看。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。