<a href="demo.jpg" download>下载图片</a>
想要实现点击加载,就能下载文件的功能。 会经常用到a标签的down属性。javascript
好比查看某图片<a href="demo.jpg">查看图片</a>
,这个代码常见,可是点击会打开一个新页面,因此关键点就是<a href="demo.jpg" download>下载图片</a>
,这里点击后就会弹出对话框保存在哪,以及编辑默认文件名。若是须要另外指定文件名的话,能够用download="demo_1.jpg"
。html
须要注意,下载文件的网页打开须要http开头不能file开头,也就是本地测试的时候,须要启动本地服务。前端
常常可能须要下载pdf excel jpg
之类的。其实能够同种操做。 若是不了解二进制数组和blob,须要看后面。java
// 前端,建个index.html文件放进这些,启动本地服务(node server.js)
// fetch的方式
fetch("/down")
.then(res => res.blob())
.then(blob => {
down(blob, "demo.pdf");
});
// 普通的方式
request("/down").then(blob => {
var blob = new Blob([blob]);
down(blob, "demo1.pdf");
});
function down(blob, filename) {
var blobURL = window.URL.createObjectURL(blob);
var a = document.createElement("a");
a.href = blobURL;
// 表示下载的
a.download = filename;
document.body.appendChild(a);
a.click();
a.remove();
window.URL.revokeObjectURL(blobURL);
}
function request(url, method = "GET") {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open(method, url);
// !!! 敲黑板 若是后端传过来的时候blob或者buffer之类的 这句必须加
xhr.responseType = "arraybuffer";
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
resolve(xhr.response);
}
};
xhr.send();
});
}
// -------- 后端 -------
// 引入本身的express路径 不用express固然也行 这就是server.js
const express = require('/usr/local/lib/node_modules/express')
let app = express()
app.listen(7777)
app.get('/',(req,res)=>{
res.sendFile(path.join(__dirname,'index.html'))
})
app.get('/down',(req,res)=>{
// 注意必须有一个demo.pdf的文件
res.download('demo.pdf')
// 浏览器打开 localhost:7777 没出错的话就能下载文件了
复制代码
其实说到这里,再来一个小玩法,好比后端传过来一串buffer怎么玩。node
// 好比后端加一个这个
app.get('/buffer',(req,res)=>{
res.send(Buffer.from('花花天下第一美'))
})
// 猜前端怎么玩
request("/buffer").then(response => {
// 提取uint8Array
let uint8 = new Uint8Array(response);
// 解决乱码
let resToString = decodeURIComponent(
escape(String.fromCharCode(...uint8))
);
// 花花天下第一美
console.log(resToString)
});
复制代码
最先出现ArrayBuffer的缘由是,js要和显卡进行数据传输(webGL),须要二进制数据类型。由此诞生二进制数组。web
二进制数组由三类对象组成。ajax
ArrayBuffer
对象:表明原始的二进制数据。是内存之中的一段二进制数据,能够经过“视图”进行操做。“视图”部署了数组接口,这意味着,能够用数组的方法操做内存。经常使用的属性byteLength
,若是分配的内存区域大,须要用这个属性检测有没有这样的空间。经常使用的方法slice
,拷贝生成一个新的ArrayBuffer对象。还有isView()
判断是否是下面两种实例。express
TypedArray
视图:用来读写简单类型的二进制数据。共包括9种类型的视图,好比Uint8Array(无符号8位整数)数组视图, Int16Array(16位整数)数组视图, Float32Array(32位浮点数)数组视图等等。json
DataView
视图:用来读写复杂类型的二进制数据。能够自定义复合格式的视图,好比第一个字节是 Uint8(无符号8位整数)、第2、三个字节是 Int16(16位整数)、第四个字节开始是 Float32(32位浮点数)等等,此外还能够自定义字节序。canvas
特色:二进制数组并非真正的数组,而是相似数组的对象。注意的是,两个视图对应的是同一段内存,一个视图修改底层内存,会影响到另外一个视图。
// 建立一个8字节的ArrayBuffer,4个格子,每一个格子是一个1个字节就是8位,就是8个由0或者1组成的数,也就是最大的存储是255,
var buffer = new ArrayBuffer(4)
// [0,0,0,0]
console.log(buffer)
// 1个格子就是8位,最大值依然255
var x1 = new Uint8Array(buffer)
// [0,0,0,0]
console.log(x1)
// 00000000 00000000 00000000 000000001 注意顺序从右往左 可是数组显示是从右往左,本身脑子绕过来[1,0,0,0]
x1[0] = 1
// 00000000 00000000 00000001 000000001 [1,1,0,0]
x1[1] = 1
// [1,1,0,0]
console.log(x1)
// 1个格子16位,就是占据2份8位的格子,每一项要*256
var x2 = new Uint16Array(buffer)
// 0000000000000000 00000001000000001 [257,0] 这样后面的就能表示更多的2次方,最大能256*256-1=65535
console.log(x2)
// 0000000000000000 00000000000000110
x2[1] = 6
console.log(x2)
// 000000000000000000000000000000110 更厉害了,不赘述
var x3 = new Uint32Array(buffer)
// 111111111111111111111111111111111 [4294967295]
x3[0] = 4294967295
console.log(x3)
// 11111111 1111111 111111 1111111 [255,255,255,255]
console.log(x1)
// 看看dataView new DataView(buffer [, byteOffset [, byteLength]]) 第几个buffer开始,长度
// view至关于 截取某段内存空间 而后以各类形式展现数据
// 00000000【3】 00000000【2】 00000000【1】 00000000【0】
var buffer = new ArrayBuffer(4)
// 同上
var view1 = new DataView(buffer)
// 上面的左边第一个 00000000 【3】 00000000【2】从索引2开始取2个个,也就是索引2和索引3
var view2 = new DataView(buffer,2,2)
// 至关于 In8Array[2] = 42 00000010【3】 00000001【2】 00000000【1】 00000000【0】
view1.setInt8(2,1)
view1.setInt8(3,2)
// 至关于 In8Array[0] 00000010【3】 00000001【2】 也就是1
console.log(view2.getInt8(0))
复制代码
ArrayBuffer的来源:
FileReader.readAsArrayBuffer()
,开始读取指定的 Blob(也就是file)中的内容, 一旦完成, result 属性中保存的将是被读取文件的 ArrayBuffer 数据对象// 举个ArrayBuffer的实例吧,发送使用XMLhttpRequest发送ArrayBuffer数据:
function sendArrayBuffer() {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server', true);
xhr.onload = function(e) { ... };
var uInt8Array = new Uint8Array([1, 2, 3]);
// 使用了类型化数组,发送的是类型化数组(uInt8Array)的buffer属性,也就是ArrayBuffer对象。
xhr.send(uInt8Array.buffer);
}
复制代码
image/jpeg
blob的来源:
new Blob(dataArr:Array<any>, options:{type:string})
建立的对象就是Blob对象。dataArray能够是二进制数组,blob,字符串,type
是数组内容的MIME类型,还有slice方法var s = '<div>1</div>'
var blob = new Blob([s],{type:'text/html'})
var abf = new ArrayBuffer(8)
var blob = new Blob([abf])
var abv = new Unit8Array(abf)
var blob = new Blob([abv])
// slice
var blob2 = blob.slice(0,3,{type:'text/plain'})
// canvas
var canvas = document.querySelector('canvas')
canvas.toBlob(function(blob){
var blob3 = blob
})
复制代码
继承blob。 file的来源:
<div id="containner">
<input type="file" id="imgFile" /><br />
<img id="previewFile" src="" height="200" alt="Image preview..." />
</div>
<script> const imgFile = document.querySelector("#imgFile"); const previewFile = document.querySelector("#previewFile"); imgFile.onchange = function(e) { // 类数组 file继承blob,每一个file有不少属性 有继承blob的type和size,还有name,lastModified(13为时间戳) let files = e.target.files; console.log(files); // previewImageByBlob(files[0],previewFile) previewImageByBase64(files[0], previewFile); }; function previewImageByBlob(blob, imgSelector) { // create必须后面是blob对象 const imgUrl = window.URL.createObjectURL(blob); // src能够是根据blob建立的url 长得像这样blob:域名/e61c67e3-df3a-453a-8f41-df740c1f5faf imgSelector.src = imgUrl; console.log(imgUrl); // 浏览器会在文档退出的时候自动释放它们,可是为了得到最佳性能和内存使用情况,你应该在安全的时机主动释放掉它们。 imgSelector.onload = function() { window.URL.revokeObjectURL(imgUrl); }; } function previewImageByBase64(blob, imgSelector) { var reader = new FileReader(); // readAsArrayBuffer readAsBinaryString readAsText 好几种类型 // 读取操做完成的时候,readyState 会变成已完成(DONE),并触发 loadend 事件,同时 result 属性将包含一个data:URL格式的字符串(base64编码)以表示所读取文件的内容,data:image/jpeg;base64,/9j/4AAQ... // 若是是服务器过来的blob,须要new Blob(blob)这样继续下面的操做 var x = reader.readAsDataURL(blob); console.log(x); // 必须监听load事件,完事了才能有完整的base64 reader.onloaded = () => { console.log("result", reader.result); imgSelector.src = reader.result; }; reader.onerror = () => { console.log("出错了"); }; } </script>
复制代码
Blob URL和Data URL有什么区别呢?
blob:域名/e61c67e3-df3a-453a-8f41-df740c1f5faf
,dataURL的显示形式data:image/jpeg;base64,/9j/4AAQ...
%XX
或者%uXXXX
这种形式escape
处理字符串,ASCII字母、数字、@*/+
这几个字符不会被编码,其他的都会encodeURI
和encodeURIComponent
处理编码URL,相似于https://juejin.im/editor/drafts/5cde6dae6fb9a07eda02e5f1
encodeURI
方法不会对下列字符编码 ,ASCII字母、数字、~!@#$&*()=:/,;?+'
,重点是/ ? # &
encodeURIComponent
方法不会对下列字符编码 ASCII字母、数字、~!*()'
unsecape encodeURI encodeURIComponent
感受不是一时半会的,待看。重点是blob.slice
有空看这篇文章
FormData对象的做用就相似于serialize({a:1,b:2}=>a=1&b=2
)方法,不过FormData是浏览器原生的,且支持二进制文件,是个一眼就会让人喜欢的很赞的东西!
// 前端
var myFormData = new FormData(form容器);
// 后端 可使用multiparty来解析form-data的数据 否则原生 的那种会有不少别的文本,难以解析
app.post('/login',(req,res)=>{
var form = new multiparty.Form();
form.parse(req, (err, fields, files)=>{
res.send(fields.username[0])
});
})
复制代码
FormData对象还有一个方法,为append()
方法,能够人为的给当前FormData对象添加一个键/值对。
myFormData.append(DOMString 键, Blob 值, [可选] DOMString 文件名);
myFormData.append(DOMString 键, DOMString 值);
// 示例 blob通常不写的话
myFormData.append('token','2h22h2j')
复制代码
down属性 formData、file,arrayBuffer数据类型 arrayBuffer 预览图片 详细的blob 大文件上传 二进制文件流实现前端下载 简单明了区分escape、encodeURI和encodeURIComponent