前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >前端:选取、预览、裁剪、上传、断点续传,关于图片上传那点事

前端:选取、预览、裁剪、上传、断点续传,关于图片上传那点事

作者头像
LIYI
发布2019-11-19 13:14:33
1.4K0
发布2019-11-19 13:14:33
举报
文章被收录于专栏:艺述论专栏艺述论专栏

所有轮子都造好了已经~

目录


01

选择

直接上代码,原生的,非类库的:

代码语言:javascript
复制
<input type="file" accept=".jpg, .jpeg, .png" capture="user" multiple />

进入 Html5 时代,在页面中开启上传功能,只需要一个 input 组件。type 代表上传,accept 代表接受的文件类型,capture 代表从摄像头拍照获取,capture="user" 代表默认打开前置摄像头,multiple 代表一次可上传多个文件。

02

剪切板上传与拖拽上传

在可编辑区域开启contenteditable,为编辑区绑定paste事件,然后处理paste 事件,从 event.clipboardData || window.clipboardData 获得数据,接着将该数据转换为文件items[i].getAsFile()。拿到 File 后,与选取就是一样的处理逻辑了。

拖拽操作的实现是类似的。定义一个允许拖放文件的区域,通过 e.preventDefault() 为该区域取消drop 事件的默认行为。监听鼠标在拖拽区域上 的 dragover 及鼠标离开拖拽区域 dragleave 事件。在拖拽区域上释放文件发生 drop 事件时,通过 e.dataTransfer.files 获得文件信息。拿到 File 后,与前面处理逻辑一样。

03

预览

以前在页面上实现预览功能,要么将图片上传到服务器上,拿到 url 再拉回本地,赋值给 img 显示;要么使用 Flash 技术。

现在好了,可以直接使用 URL.createObjectURL 将 input[file] 选择的文件在用户本地转化为一个 可以赋值给 img 组件 src 属性的图片地址。

代码语言:javascript
复制
const $ = document.getElementById.bind(document);...$inputFile.addEventListener('change', function() {const file = this.files[0];  $previewImage.src = URL.createObjectURL(file);}, this);

这段代码看起来很简洁,$ 绑定在 document 对象上,不引入 JQuery 或 Zepto,也可以优雅地查找页面元素。使用 addEventListener 监听 input[file] 的 change 事件,当用户选择图片文件时,调用 URL.createObjectURL(file) 将 File 对象转化为可被 img 组件接受并预览的图片地址。

除了 使用 URL.createObjectURL,还可以使用 FileReader 。

代码语言:javascript
复制
const file = this.files[0];const reader = new FileReader();reader.addEventListener('load', function() {  $previewImage.src = reader.result;}, false);
if(file) {  reader.readAsDataURL(file);}

FileReader 是异步的,且只能加载安全沙箱之内的用户内容,它并不能像其它语言的 file 模块那样在用户的文件系统中按路径随意读取文件。

实现预览功能,直接使用 URL.createObjectURL 实现即可,更简洁。

04

裁剪

实现选取、裁剪图片部分区域的功能。直接使用下面这个库:

https://github.com/fengyuanchen/cropperjs

可定制,基本能满足所有需求;也可以基于 MIT 协议修改。

代码语言:javascript
复制
function showCropper() {$cropper.style.display = 'block';cropperInstance && cropperInstance.destroy();cropperInstance = new Cropper($cropperImage, {  viewMode: 1,  aspectRatio: 1,  autoCropArea: 1,  dragMode: 'move',  guides: false,  highlight: false,  cropBoxMovable: false,  cropBoxResizable: false});}

05

上传

使用 new FormData 可以直接构建表单数据对象,然后发送给服务器:

代码语言:javascript
复制
const formData = new FormData();formData.append('avatar', blob);fetch('server url', {  method: 'POST',  body: formData});

旧方式拼接 XMLHttpRequest 请求体的朝代已经一去不复返了:

06

断点续传

有时候文件比较大,或网络环境不稳定,需要实现分片上传及断点续传;有时候单纯为了追求上传速度,希望将浏览器 6 个并发连接跑满,所以也希望实现分片上传。

方案很简单。从 input[file] 选择拿到的对象是一个 File 对象,它继续于 Blob。Blob 对象表示一个不可变、原始数据的类文件对象,并且有一个 slice 方法,可以将自身分割为多个小段的 Blob 对象。每个小段 Blob 是可以单独发给服务器的。

代码语言:javascript
复制
let chunkSize=2*1024*1024;//分片大小 2Mlet file = document.getElementById('f1').files[0];if(file.size>chunkSize){let start=0,end=0;while (true) {        end += chunkSize;let blob = file.slice(start,end);        start+=chunkSize;        ...        chunks.push(blob);//保存分段数据    }}else{    chunks.push(file.slice(0));}

截段之后,还需要一个 js-spark-md5 类库:

https://github.com/satazor/js-spark-md5

这是一个在本地就可以给 Blog 对象签名生成唯一标识的类库,只要上传的是同一个文件,只要分段大小一致,网络断了再次上传,生成的标识也是一样的。每次上传完一个切片,就将标识存储在本地,页面刷新后先看看本地哪些分片已经上传过了。

— END —

2019 年冬天于北京


往期精选

JS是如何计算 1+1=2 的?

微信为什么要搞一个小游戏?

前端:浏览器、GPU 工作原理简要及动画编程启示

篆刻漫谈一二

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-11-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 艺述论 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档