图片上传知识点梳理

在日常项目开发中,图片上传是一个十分常见的场景。而现在的各种UI框架都提供了自己的上传组件,网上第三方的上传组件也多如牛毛。可能你早已习惯了直接使用这些现成的组件,然而对于其具体的实现,却并未深入解析。本文将通过简单的代码,为你解析图片上传的各个知识点。

样式自定义

既然是上传,肯定需要使用到<input type="file">标签了。然而,默认的input到标签样式不仅单一,且在各个浏览器下的表现也不相同,所以通常需要对input进行样式自定义。但<input>标签对于样式的修改并不十分友好。解决方法很多,最常用的是将<input type="file">标签隐藏,然后通过一个<label>标签进行关联,然后直接修改<label>标签的样式来实现。代码如下:

    &lt;input type="file" id="uploadImg"&gt;&lt;label for="uploadImg"&gt;点击上传&lt;/label&gt;

图片校验

在上传之前,一般会对文件进行各种校验,例如文件类型,大小,格式,尺寸等。

其中文件类型,可通过设置<input>标签的accept来指定文件类型。但accept属性并不能完全禁止用户上传指定类型之外的文件。故可以通过上传文件的各个属性进行校验拦截。校验前,我们需要通过change事件的事件对象来获取到上传的文件:

    event.target.files

可以获取到上传文件列表。列表中对象包含如下信息:

    {lastModified: 1524153515000lastModifiedDate: Thu Apr 19 2018 23:58:35 GMT+0800 (中国标准时间) {}name: "589adfbfe821c.jpg"size: 1357444type: "image/jpeg"webkitRelativePath: ""}

从该对象中,我们可以获取到文件大小,文件类型,文件名等信息,从而可以在上传之前对这些信息进行校验,从而拦截掉不合法的文件。

然而,从file对象中,我们并不能获取图片的尺寸信息。而在我们的业务中,很多场景都需要限制上传图片的尺寸为某一个固定值,或者是某一个比例。以减少后期显示时的适配问题。要实现对上传图片尺寸对校验,我们需要使用到FileReader和Image。

FileReader对象允许Web应用程序异步读取存储在用户计算机上的文件。

Image()函数将会创建一个新的HTMLImageElement实例。它的功能等价于document.createElement('img')

这里,我们需要用到fileReaderreadAsDataURL()方法来读取上传文件信息,通过onload处理事件来获取读取到的文件信息。如下:

    const reader = new FileReader();reader.readAsDataURL(file);reader.onload = e =&gt; {console.log(e.target.result)}

代码中,file为我们之前获取到的文件列表files中的文件对象。e.target.result为读取到到文件内容。

之后通过new Image()函数创建一个新的HTMLImageElement实例,并将该实例的src赋值为fileReader读取到到文件内容。即可得到一个该文件的HTMLImageElement实例,通过该实例,我们便可以读取到该图片的尺寸信息。具体代码如下:

    const image = new Image();image.src = e.target.result;image.onload = () =&gt; {console.log(image.width, image.height);}

图片上传预览

在之前的开发中,图片上传显示通常会采用先将文件上传,预览图片直接展示上传到服务器中到图片来实现,但这样无法达到上传前预览该图片的目的,且会造成许多垃圾图片的上传。

通过前面对于获取图片尺寸研究。相信你能很快想到一种更加优雅的图片预览方案,既然我们已经获取到了该文件的HTMLImageElement实例,那么我们直接将该实例append到页面的容器Dom中不久行了。或者直接将获取到的文件设置到已存在的image标签的src属性中。图片上传预览就是这么简单。

图片上传与上传进度展示

图片的上传,我们可以直接通过form标签搭配表单的submit()方法来实现图片的上传。然而,这样我们就无法在上传前进行上传文件的校验与拦截。同时需要用户主动触发提交操作。要想让我们之前做的上传前的拦截工作不白做,我们需要去在合适的时候,主动触发文件的上传操作。

这里,需要使用到FormData对象,来将入参对象数据转为表单数据。

FormData对象用以将数据编译成键值对,以便用XMLHttpRequest来发送数据。其主要用于发送表单数据,但亦可用于发送带键数据(keyed data),而独立于表单使用。如果表单enctype属性设为multipart/form-data ,则会使用表单的submit()方法来发送数据,从而,发送数据具有同样形式。

首先我们创建一个formData对象,然后通过append() 方法来添加字段。如下:

    const formData = new FormData();formData.append("file", file);

注意,formData虽然为一个对象,但通过console.log却无法打印出其具体的值,只会得到FormData {}

接下来创建一个XMLHttpRequest对象,用来发送ajax请求。并且通过该XMLHttpRequest对象的upload.onprogress方法,可以实时获取到上传信息,并进一步获取到上传的进度。具体代码如下:

    const client = new XMLHttpRequest()client.open("POST", uploadUrl)client.upload.onprogress = function(e) {if (e.lengthComputable) {let total = e.total;let loaded = e.loaded;let percentage = parseFloat(loaded / total).toFixed(2);}}client.send(formData)

上面代码中,uploadUrl为上传的URL。通过upload.onprogress的事件对象,可以获取到当前进度已上传的文件大小以及完整文件大小,通过这两个大小参数,可以很容易计算出已上传文件的比例,之后是显示上传进度条、还是展示进度数据,就可以随意操作了。

拖拽上传

除了传统的点击选择上传文件外,拖拽文件上传也是一个十分常见的场景。要使用拖拽上传,就需要使用H5的拖放方法dropdrag方法。除了这两个主要的方法外,还有拖放的不同阶段触发的多个方法,常用的拖拽方法如下:

  • ondragstart 事件:当拖拽元素开始被拖拽的时候触发的事件(作用对象为被拖曳元素)
  • ondrag:在元素拖动期间不停的触发该事件,与touchmove事件类似。(作用对象为被拖曳元素)
  • ondragend 事件:当拖拽完成后触发的事件(作用对象为被拖曳元素)
  • ondragenter 事件:当拖曳元素进入目标元素的时候触发的事件(作用对象为目标元素)
  • ondragover 事件:拖拽元素在目标元素上移动的时候触发的事件(作用对象为目标元素)
  • ondragleave 事件:拖拽元素在目标元素上移动的时候触发的事件(作用对象为目标元素)
  • ondrop 事件:被拖拽的元素在目标元素上同时鼠标放开触发的事件(作用对象为目标元素)

拖拽的各个事件类似与touch事件的各个阶段。然而需要注意的是,拖拽的各个事件,有着自己的作用对象,作用对象分为‘被拖拽元素’和‘目标元素’。被拖拽元素 为拖拽的那个Dom元素,主要使用在页面内Dom拖拽移动的场景。目标元素为接收被拖拽元素的元素区域。当被拖拽元素进入到该区域,便会触发目标对象的一系列事件。

在图片拖拽上传这个业务场景中,被拖拽元素为页面外部的图片文件,故此处仅用到目标元素的各个事件。我们可以通过这些事件来修改目标区域样式等。核心的两个事件为ondragoverondrop事件。可能你觉得我只需要在松开鼠标时获取拖拽的文件就行,因此只需要使用ondrop事件就行了?但是,由于浏览器的默认行为,ondrop事件并不会被触发。因此,需要使用e.preventDefault(); 来阻止掉 ondropover的浏览器默认事件,从而保证ondrop事件的触发。通过ondrop事件的事件对象,我们可以获取到跟event.target.files相同的文件列表,获取方法为event.dataTransfer.files;然而,当你这么写完之后,进行拖拽之后,你会发现浏览器自动跳转到了该图片的预览页。这也是由于浏览器的默认行为导致,因此也需要使用e.preventDefault();来阻止掉浏览器的默认行为。这样,便可以进行后续的文件校验操作来。
具体实现代码如下:

    &lt;label for="uploadImg"onDragOver={e =&gt; {e.preventDefault();}}onDrop={e =&gt; {if (e.dataTransfer) {e.preventDefault();const file = e.dataTransfer.files[0];...} }}&lt;/label&gt;

至此,图片上传的常用知识点以梳理完毕,欢迎补充。

原文地址:https://segmentfault.com/a/1190000016920382

转载于:https://www.cnblogs.com/lalalagq/p/9921316.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/450789.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决 java.lang.IllegalArgumentException: Repository interface must not be null on initialization!

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 报错&#xff1a;Caused by: java.lang.IllegalArgumentException: Repository interface must not be null on initialization! Cause…

【狂神说】JVM

文章目录1.JVM的位置2.JVM的体系结构3.类加载器4.双亲委派机制&#xff08;重要&#xff09;5.沙箱安全机制(了解)6.native&#xff08;核心&#xff09;7.PC寄存器&#xff08;了解&#xff09;8.方法区9.栈10.三种JVM11.堆&#xff08;Heap&#xff09;12.新生区、老年区13.永…

我们真的需要统一的编程规范?

摘要&#xff1a;仁者见仁智者见智&#xff0c;编码风格的不同&#xff0c;对项目也会有不同的影响&#xff0c;统一的编码规范有益于项目的维护。俗话说&#xff0c;没有规矩不成方圆&#xff0c;在2004年&#xff0c;UNIX创始人之一的Ken Arnold就发表了一篇很幽默文章&#…

百度云重磅发布ABC 3.0 尹世明如何诠释百度云的“新”打法

雷锋网9月4日消息&#xff0c;2018百度云智峰会正式召开&#xff0c;百度总裁张亚勤发表题为《新技术驱动&#xff0c;全面进入Cloud2.0》的演讲并表示&#xff0c;经历了PCClient/Server到MobileCloud 1.0&#xff0c;再到如今的AICloud 2.0过程&#xff0c;新技术推动云计算产…

EcmaScript对象克隆之谜

先谈谈深拷贝 如何在js中获得一个克隆对象&#xff0c;可以说是喜闻乐见的话题了。相信大家都了解引用类型与基本类型&#xff0c;也都知道有种叫做深拷贝的东西&#xff0c;传说深拷贝可以获得一个克隆对象&#xff01;那么像我这样的萌新自然就去学习了一波&#xff0c;我们能…

开发人员眼中最好的代码编辑器是谁?

摘要&#xff1a;对开发人员来讲&#xff0c;开发工具就好比战场上的“兵器”&#xff0c;不同领域的开发人员他们所使用的“兵器”也不完全相同&#xff0c;本文从友好性、功能性、扩展等多方面总结了最受开发人员欢迎的“兵器”。你最爱的那个在这里吗&#xff1f; 如果我们把…

关于RESTful一些注意事项,接口开发规范

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 最近在研究restful&#xff0c;公司开发要使用&#xff0c;所以自己就去网上找了好些资料&#xff0c;并整理了一套公司开发的接口规范。…

【老杜】MySQL—day01

文章目录day01课堂笔记1、数据库概述及数据准备1.1、什么是数据库1.2、什么是数据库管理系统1.3、SQL概述1.4、安装MySQL数据库管理系统。1.4、MySQL数据库的完美卸载&#xff01;1.5、MySQL的服务1.6、用命令来启动和关闭mysql服务1.7、登录mysql数据库2、MySQL常用命令&#…

【转载】DRuid 大数据分析之查询

转载自http://yangyangmyself.iteye.com/blog/23217591、Druid 查询概述上一节完成数据导入后&#xff0c;接下来讲讲Druid如何查询及统计分析导入的数据。Druid的查询是使用REST风格的HTTP请求查询服务节点&#xff08;Broker、Historical、Realtime&#xff09;&#xff0c;这…

记录 Parameter with that position [1] did not exist; nested exception is java.lang.IllegalArgumentExce

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 报错如题&#xff1a; Parameter with that position [1] did not exist; nested exception is java.lang.IllegalArgumentException: Pa…

[转]简单的动态修改RDLC报表页边距和列宽的方法

本文转自&#xff1a;http://star704983.blog.163.com/blog/static/136661264201161604413204/ 1.修改页边距 XmlDocument XMLDoc new XmlDocument();XMLDoc.Load(System.Windows.Forms.Application.StartupPath "\Report_try-2.rdlc");XmlNamespaceManager xmn n…

函数式编程语言天生就慢吗?

摘要&#xff1a;近期&#xff0c;函数式编程得到了越来越多的关注&#xff0c;Lisp不仅重获青春还涌现出了一批新函数式编程语言。因此开发者们对函数式编程语言的运行快慢各抒己见&#xff0c;展开激烈讨论。本文将和大家一起讨论&#xff0c;函数式编程语言真的就慢吗&#…

【老杜】MySQL—day02

文章目录day02课堂笔记1、把查询结果去除重复记录【distinct】10、连接查询10.1、什么是连接查询&#xff1f;10.2、连接查询的分类&#xff1f;10.3、当两张表进行连接查询时&#xff0c;没有任何条件的限制会发生什么现象&#xff1f;10.4、怎么避免笛卡尔积现象&#xff1f;…

vue根据数组对象中某个唯一标识去重

由于在vue中&#xff0c;会自动在数组和对象中加入_obser__观察者模式的一些属性&#xff0c;所以直接用数组的filter去重&#xff08;下面这种&#xff09;&#xff0c;indexOf不能准确识别 var arr [1, 2, 2, 3, 4, 5, 5, 6, 7, 7]; var arr2 arr.filter(function(x, index…

Springsecurity之AuthenticationProvider

2019独角兽企业重金招聘Python工程师标准>>> 注意&#xff1a;AuthenticationProvider与Authentication紧密联系&#xff0c;关于Authentication&#xff0c;看我的这篇博客。 先上一张图&#xff0c;如下图1 图1 AuthenticationProvider的类图 AuthenticationProvi…

Postman使用入门

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Postman测试管理的单位是测试集&#xff08;Collections&#xff09;&#xff0c;测试集内可以创建文件夹(Folder)和具体的请求(Requests…

编程需要知道多少数学知识?

摘要&#xff1a;许多人认为在开始学习编程之前必须对数学很在行或者数学分数很高。但一个人为了编程的话&#xff0c;需要学习多少数学呢&#xff1f; 实际上不需要很多 。这篇文章中我会深入探讨编程中所需要的数学知识。 下面是我在reddit的子论坛 r/learnprogramming 看到的…

HDU 6071 Lazy Running

链接HDU 6071 Lazy Running 给出四个点1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;1和2&#xff0c;2和3&#xff0c;3和4&#xff0c;4和1之间有路相连&#xff0c;现在从2点出发&#xff0c;最后回到2点&#xff0c;要求路径大于等于\(K\)&#xff0c;问路径长度最…

vue弹窗插件实战

vue做移动端经常碰到弹窗的需求, 这里写一个功能简单的vue弹窗 popup.vue <template><div class"popup-wrapper" v-show"visible" click"hide"><div class"popup-text">{{text}}</div></div> </temp…