前端下载文件以及上传图片预览,顺便了解arrayBuffer和blob

本文涉及的产品
可视分析地图(DataV-Atlas),3 个项目,100M 存储空间
数据可视化DataV,5个大屏 1个月
简介: 前端下载文件以及上传图片预览,顺便了解arrayBuffer和blob

前端下载文件以及上传图片预览,顺便了解arrayBuffer和blob


TL;DR

前端下载的关键靠下载图片

后端传blob,前端处理blob,然后下载文件

二进制数组arrayBuffer、typedArray、dataView相关内容

blob、file相关内容

上传图片预览的两种方式:blobURL和dataURL

下载的关键----a的download属性

想要实现点击加载,就能下载文件的功能。 会常常用到a标签的down属性。

比如查看某图片查看图片,这个代码常见,但是点击会打开一个新页面,所以关键点就是下载图片,这里点击后就会弹出对话框保存在哪,以及编辑默认文件名。如果需要另外指定文件名的话,可以用download="demo_1.jpg"

需要注意,下载文件的网页打开需要http开头不能file开头,也就是本地测试的时候,需要启动本地服务。

前端实现下载任意服务器的任意的文件

经常可能需要下载pdf excel jpg之类的。其实可以同种操作。 如果不了解二进制数组和blob,需要看后面。

// 前端,建个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怎么玩。

// 比如后端加一个这个
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

最早出现ArrayBuffer的原因是,js要和显卡进行数据传输(webGL),需要二进制数据类型。由此诞生二进制数组。

二进制数组由三类对象组成。

ArrayBuffer对象:代表原始的二进制数据。是内存之中的一段二进制数据,可以通过“视图”进行操作。“视图”部署了数组接口,这意味着,可以用数组的方法操作内存。常用的属性byteLength,如果分配的内存区域大,需要用这个属性检测有没有这样的空间。常用的方法slice,拷贝生成一个新的ArrayBuffer对象。还有isView()判断是不是下面两种实例。

TypedArray视图:用来读写简单类型的二进制数据。共包括9种类型的视图,比如Uint8Array(无符号8位整数)数组视图, Int16Array(16位整数)数组视图, Float32Array(32位浮点数)数组视图等等。

DataView视图:用来读写复杂类型的二进制数据。可以自定义复合格式的视图,比如第一个字节是 Uint8(无符号8位整数)、第二、三个字节是 Int16(16位整数)、第四个字节开始是 Float32(32位浮点数)等等,此外还可以自定义字节序。

特点:二进制数组并不是真正的数组,而是类似数组的对象。注意的是,两个视图对应的是同一段内存,一个视图修改底层内存,会影响到另一个视图。

// 创建一个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的来源:

new ArrayBuffer(8)

从本地文件读取,利用FileReader.readAsArrayBuffer(),开始读取指定的 Blob(也就是file)中的内容, 一旦完成, result 属性中保存的将是被读取文件的 ArrayBuffer 数据对象

从base64 字符串获取

通过ajax请求获取  设置responseType 为  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);
}

blob

一个 Blob 对象表示一个不可变的,原始数据的类似文件对象。是存放二进制数据的容器。但是是类似文件对象的二进制数据。二进制数组不一定是一个文件对象。

blob实例有两个属性,size和type,size以字节为单位,type如image/jpeg

File 对象是特殊类型的 Blob

blob的来源:

通过new Blob(dataArr:Array, options:{type:string})创建的对象就是Blob对象。dataArray可以是二进制数组,blob,字符串,type是数组内容的MIME类型,还有slice方法

XMLHttpRequest里,如果指定responseType为blob,那么得到的返回值也是一个blob对象

canvas对象上的toBlob方法

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
})

file

继承blob。 file的来源:

可以是来自用户在一个input元素上选择文件后返回的FileList对象

可以是来自拖放操作生成的 DataTransfer对象

可以是来自在一个HTMLCanvasElement上执行mozGetAsFile()方法后返回结果

实践:上传图片预览的功能

<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显示的形式blob:域名/e61c67e3-df3a-453a-8f41-df740c1f5faf ,dataURL的显示形式data:image/jpeg;base64,/9j/4AAQ...

Blob URL的长度一般比较短,但Data URL因为直接存储图片base64编码后的数据,往往很长,如上图所示,浏览器在显示Data URL时使用了省略号(…)。当显式大图片时,使用Blob URL能获取更好的可能性。

Blob URL可以方便的使用XMLHttpRequest获取源数据(xhr.responseType = 'blob')。对于Data URL,并不是所有浏览器都支持通过XMLHttpRequest获取源数据的

Blob URL 只能在当前应用内部使用,把Blob URL复制到浏览器的地址栏中,是无法获取数据的。Data URL相比之下,就有很好的移植性,你可以在任意浏览器中使用。

Blob URL除了可以用作图片资源的网络地址,Blob URL也可以用作其他资源的网络地址,例如html文件、json文件等,为了保证浏览器能正确的解析Blob URL返回的文件类型,需要在创建Blob对象时指定相应的type

区分escape、encodeURI和encodeURIComponent

编码之后的效果是%XX或者%uXXXX这种形式

escape处理字符串,ASCII字母、数字、@*/+ 这几个字符不会被编码,其余的都会

encodeURIencodeURIComponent处理编码URL,类似于https://juejin.im/editor/drafts/5cde6dae6fb9a07eda02e5f1

encodeURI方法不会对下列字符编码 ,ASCII字母、数字、~!@#$&*()=:/,;?+',重点是/ ? # &

encodeURIComponent方法不会对下列字符编码 ASCII字母、数字、~!*()'

相应的解码unsecape encodeURI encodeURIComponent

综合使用,分片上传

感觉不是一时半会的,待看。重点是blob.slice有空看这篇文章

formdata

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

相关实践学习
DataV Board用户界面概览
本实验带领用户熟悉DataV Board这款可视化产品的用户界面
阿里云实时数仓实战 - 项目介绍及架构设计
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3&nbsp;)前置知识要求 &nbsp; 课程大纲 第一章&nbsp;了解数据仓库概念 初步了解数据仓库是干什么的 第二章&nbsp;按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章&nbsp;数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章&nbsp;采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章&nbsp;用户行为数据仓库 严格按照企业的标准开发 第六章&nbsp;搭建业务数仓理论基础和对表的分类同步 第七章&nbsp;业务数仓的搭建&nbsp; 业务行为数仓效果图&nbsp;&nbsp;
目录
相关文章
|
2月前
|
前端开发
前端引入字体文件
文章介绍了如何在前端项目中引入字体文件,并展示了具体的HTML和CSS代码示例,包括如何使用`@font-face`规则来定义字体和在页面中应用自定义字体。
67 1
前端引入字体文件
|
24天前
|
前端开发 API
前端界面生成PDF并导出下载
【10月更文挑战第21天】利用合适的第三方库,你可以在前端轻松实现界面生成 PDF 并导出下载的功能,为用户提供更方便的文档分享和保存方式。你还可以根据具体的需求进一步优化和定制生成的 PDF 文件,以满足不同的业务场景要求。
|
1月前
|
前端开发 JavaScript
💥【exceljs】纯前端如何实现Excel导出下载和上传解析?
本文介绍了用于处理Excel文件的库——ExcelJS,相较于SheetJS,ExcelJS支持更高级的样式自定义且易于使用。表格对比显示,ExcelJS在样式设置、内存效率及流式操作方面更具优势。主要适用于Node.js环境,也支持浏览器端使用。文中详细展示了如何利用ExcelJS实现前端的Excel导出下载和上传解析功能,并提供了示例代码。此外,还提供了在线调试的仓库链接和运行命令,方便读者实践。
305 5
|
1月前
|
JavaScript 前端开发 编译器
吐血整理:纯前端如何实现批量dom转图片,并下载成压缩包
【10月更文挑战第2天】吐血整理:纯前端如何实现批量dom转图片,并下载成压缩包
55 2
|
1月前
|
资源调度 前端开发 安全
前端实战:基于Verdaccio搭建私有npm仓库,轻松上传与下载自定义npm插件包
前端实战:基于Verdaccio搭建私有npm仓库,轻松上传与下载自定义npm插件包
82 0
|
1月前
|
JavaScript 前端开发 应用服务中间件
vue前端开发中,通过vue.config.js配置和nginx配置,实现多个入口文件的实现方法
vue前端开发中,通过vue.config.js配置和nginx配置,实现多个入口文件的实现方法
143 0
|
1月前
|
前端开发 JavaScript API
前端基于XLSX实现数据导出到Excel表格,以及提示“文件已经被损坏,无法打开”的解决方法
前端基于XLSX实现数据导出到Excel表格,以及提示“文件已经被损坏,无法打开”的解决方法
130 0
|
2月前
|
存储 JSON 前端开发
栈在前端中的应用,顺便再了解下深拷贝和浅拷贝!
该文章探讨了栈在前端开发中的应用,并深入讲解了JavaScript中深拷贝与浅拷贝的区别及其实现方法。
栈在前端中的应用,顺便再了解下深拷贝和浅拷贝!
|
2月前
|
前端开发 JavaScript C++
详解链表在前端的应用,顺便再弄懂原型和原型链!
该文章深入解析了链表在前端开发中的应用,并详细阐述了JavaScript中的原型和原型链的概念及其工作原理。
|
2月前
|
移动开发 前端开发 JavaScript
使用html-to-image代替html2canvas,结合jspdf实现下载pdf(下载截图下载前端dom元素)
本文介绍了在前端项目中,当使用`html2canvas`遇到问题时,如何使用`html-to-image`库作为替代方案,结合`jspdf`实现将DOM元素生成为PDF文件并提供下载。文章首先讨论了`html2canvas`可能遇到的问题,并提供了该库的使用示例代码。随后,详细介绍了`html-to-image`库的安装和使用方法,展示了如何将DOM元素转换为Canvas,再利用`jspdf`生成PDF文件。最后,文章通过示例代码说明了整个转换和下载的过程,并展示了效果截图。
90 0