最近很好奇前端的文件上传功能,因为公司要求做一个支持图片预览的图片上传插件,所以自己搜了很多相关的插件,虽然功能很多,但有些地方不能根据公司的想法去修改,而且需要依赖jQuery或Bootstrap库,所以我就想学下图片上传的原理,试着做一个原生无依赖,而且足够灵活的图片上传插件。话不多说,开整。

1. 大体思路

1.1 首先我们需要考虑用户如何使用我们的插件。

用户引入插件代码后,只需要像下面这样,设置一些参数,然后执行一个方法就生成一个图片上传组件。

  1. <div id="upload"></div> // 这是用来生成图片上传组件的div
  1. <script>
  2. // 设置参数
  3. var options = {
  4. path: '/', // 上传图片时指定的地址路径,类似form变淡的action属性
  5. onSuccess: function (res) { // 上传成功后执行的方法,res是接收的ajax响应内容
  6. console.log(res);
  7. },
  8. onFailure: function (res) { // 上传失败后执行的方法,res是接收的ajax响应内容
  9. console.log(res);
  10. }
  11. }
  12. // 执行生成图片上传插件的方法, 第一个参数是上面提到的准备生成组件的div选择器,第二个参数是设置的组件信息,执行方法后返回一个函数指针,指向执行上传功能的函数,通过把执行上传功能的函数暴露出来,用户就可以自己控制何时上传图片了。
  13. var upload = tinyImgUpload('#upload', options);
  14. </script>

1.2 代码设计

我们需要思考用户如何引入我们的插件代码。

插件代码应该分为两个文件,一个CSS文件(tinyImgUpload.css),用于定义组件的基本样式,此外用户可以根据自己的想法自己DIY样式,另一个是控制功能逻辑的js文件(tinyImgUpload.js)。用户引入这两个文件后,就可以实现图片上传组件了。

2. 具体实现

具体实现的时候,主要涉及到两个地方,一个是读取本地文件,实现图片上传前可以预览的功能,一个是图片上传功能。

2.1 读取本地文件实现预览

这里用到了html5的File API,使用这个API可以在客户端验证上传的文件类型,限制文件大小,当然,在这里我们主要用到FileReader接口来读取文件,Filereader.readAsDataURL()返回的事件对象的result属性就是将文件编码为base64的数据地址,类似下面这样的,把他赋值给src属性,图片就显示出来了。



具体代码如下,完整代码可以从这里下载(tinyImgUpload.js

  1. // 预览图片
  2. //处理input选择的图片
  3. function handleFileSelect(evt) {
  4. var files = evt.target.files;
  5. for(var i=0, f; f=files[i];i++){
  6. // 过滤掉非图片类型文件
  7. if(!f.type.match('image.*')){
  8. continue;
  9. }
  10. // 过滤掉重复上传的图片
  11. var tip = false;
  12. for(var j=0; j<(ele.files).length; j++){
  13. if((ele.files)[j].name == f.name){
  14. tip = true;
  15. break;
  16. }
  17. }
  18. if(!tip){
  19. // 图片文件绑定到容器元素上
  20. ele.files.push(f);
  21. var reader = new FileReader();
  22. reader.onload = (function (theFile) {
  23. return function (e) {
  24. var oDiv = document.createElement('div');
  25. oDiv.className = 'img-thumb img-item';
  26. // 向图片容器里添加元素
  27. oDiv.innerHTML = '<img class="thumb-icon" src="'+e.target.result+'" />'+
  28. '<a href="javscript:;" class="img-remove">x</a>'
  29. ele.insertBefore(oDiv, addBtn);
  30. };
  31. })(f);
  32. reader.readAsDataURL(f);
  33. }
  34. }
  35. }
  36. // input#img-file-input是一个隐藏的上传图片的input控件,当选择图片的时候会触发change事件
  37. document.querySelector('#img-file-input').addEventListener('change', handleFileSelect, false);

2.2 上传图片

2.2.1 准备文件对象

上传文件之前,我们需要考虑如何保存用户已经选择的文件对象,由于用户可能多次选择,也可能在上传之前又删除了几个图片,所以需要有一个地方实时保存图片信息,并且要和预览的图片保持同步,预览显示有哪几张图片,这个地方就存储几张图片。我采用的方式是将文件信息组装成一个数组,然后绑定到组件元素(#img-container)的自定义属性上,上面代码中的“ele.files.push(f)”做的就是这件事。

2.2.2 文件对象我们准备好后,下一步就是上传了

ajax是不能直接上传文件对象的,我们可以通过FormData对象,FormData是XMLHttpRequest Level 2添加的一个新接口,使用一系列的键值对来模拟一个完整的表单,然后使用XMLHttpRequest异步发送这个"表单"。具体代码如下。

  1. // 上传图片
  2. function uploadImg() {
  3. var xhr = new XMLHttpRequest();
  4. var formData = new FormData();
  5. for(var i=0, f; f=ele.files[i]; i++){
  6. formData.append('files', f);
  7. }
  8. xhr.onreadystatechange = function (e) {
  9. if(xhr.readyState == 4){
  10. if(xhr.status == 200){
  11. options.onSuccess(xhr.responseText);
  12. }else {
  13. options.onFailure(xhr.responseText);
  14. }
  15. }
  16. }
  17. xhr.open('POST', options.path, true);
  18. xhr.send(formData);
  19. }

2.3 设置样式

我们写了一个基本的布局样式作为默认样式,用户可以根据自己的需求进行DIY。这里是完整的样式文件(tinyImgUpload.css )。

基本的效果图如下。



如果我们想触发上传图片,可以把tinyImgUpload('#upload', options)返回的upload方法绑定到一个按钮上,监听点击事件。

  1. <button class="submit">submit</button>
  2. <script>
  3. document.getElementsByClassName('submit')[0].onclick = function (e) {
  4. upload();
  5. }
  6. </script>

这样当我点击图片的时候,图片就会上传,交给服务器端处理了。



上传按钮



服务器接收的图片

为了测试图片上传好不好用,我自己搭建了一个图片接收的服务器,使用的是node.js,通过multer实现,如果大家感兴趣可以点击这里

3 总结

图片上传的关键部分就是如何读取本地文件实现预览,以及通过FormData对象构造一个表单对象实现ajax异步上传文件。目前这个插件的功能还不够完善,我把它放到了Github上(https://github.com/gitwd/tinyImgUpload),后续会慢慢优化,欢迎大家提出宝贵意见。

4 参考目录

https://www.html5rocks.com/en/tutorials/file/dndfiles/

http://codecloud.net/9276.html

http://www.zhangxinxu.com/wordpress/2011/09/基于html5的可预览多图片ajax上传/

https://cnodejs.org/topic/50ce2bbb637ffa415589a50f

上传图片,多图上传,预览功能,js原生无依赖的更多相关文章

  1. JavaScript实现本地图片上传预览功能(兼容IE、chrome、FF)

    需要解决的问题有:本地图片如何在上传前预览.编辑:最近发现这个功能很多是基于flash实现的,很多JavaScript实现的代码兼容性都很差,特别是在IE和firefox和chrome三个浏览器上不兼 ...

  2. JQ实现图片上传预览功能

    <input type="file" name="img" id="test1"> <img src="&quo ...

  3. js实现图片上传预览功能,使用base64编码来实现

    实现图片上传的方法有很多,这里我们介绍比较简单的一种,使用base64对图片信息进行编码,然后直接将图片的base64信息存到数据库. 但是对于系统中需要上传的图片较多时并不建议采用这种方式,我们一般 ...

  4. React + js-xlsx构建Excel文件上传预览功能

    首先要准备react开发环境以及js-xlsx插件 1. 此处省略安装react安装步骤 2.下载js-xlsx插件 yarn add xlsx 或者 npm install xlsx 在项目中引入 ...

  5. hTML5 多图上传预览

    <p> <label>请选择一个文件:</label> <input type="file" id="file" mu ...

  6. 使用ajax,结合jquery,php实现图片上传预览功能

    大致逻辑:点击页面的file,上传图片到指定的php处理图片的文件,处理完成以后,将图片的连接地址返回,JS控制返回的数据,然后将图片动态的展示出来html代码<label> <im ...

  7. HTML+Jquery实现多图片上传预览功能

    HTML:使用input的onchange事件,它一改变就触发事件 <p id="p3"> <input name="File" onchan ...

  8. js 移动端 多图上传 预览 删除 base64转为url 传给后端

    说下主要的逻辑,首先是利用input type="file",上传文件,然后判断文件类型是否是图片,这里要注意(multiple,安卓一次一张,ios可以多张). 接着把本地图片转 ...

  9. js实现图片上传预览功能,使用base64编码来实现

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  10. jQuery插件ImgAreaSelect 实例讲解一(头像上传预览和裁剪功能)

    上一节随笔中,我们已经知道了关于jQuery插件ImgAreaSelect基本的知识:那么现在看一下实例: 首先,要知道我们应该实现什么功能? (1)图片能够实现上传预览功能 (2)拖拽裁剪图片,使其 ...

随机推荐

  1. 使用jquery时一些小技巧的总结

    使用 each 遍历 var nodes = Ztree.getCheckedNodes(true); //获取所有勾选的节点 $.each(nodes,function(i,value){ aler ...

  2. Zepto.js-事件处理

    http://www.webdevs.cn/article/68.html     web开发网 事件 $.Event $.Event(type, [properties]) ⇒ event 创建并初 ...

  3. OC类方法的调用

    有个Person类,有个Phone类,Person类想使用Phone类中打电话和发短信的方法 1.Phone.h         Phone有kind和color属性  ,方法定义的时候将用到的参数都 ...

  4. JQuery动画animate的stop方法使用详解

    JQuery动画animate的stop方法使用详解 animate语法: 复制代码 代码如下: $(selector).animate(styles,speed,easing,callback) 复 ...

  5. JavaScript的4种this调用模式

    方法调用模式:函数调用模式:构造器调用模式:apply调用模式: 方法调用模式: 当一个函数被保存为对象的一个属性时,我们称它为一个方法.当一个方法被调用时,this被绑定到该对象. 函数调用模式: ...

  6. MyBatis 一对一关联查询

    xml文件: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC & ...

  7. 如何使用Ninja快速编译LLVM和Clang

    在使用Make工具编译LLVM是非常耗时的.往往需要三四个小时.但是使用goolge开源的ninja编译LLVM只需要10到20分钟. 本文以llvm3.3为例,演示在linux上编译和安装过程. 第 ...

  8. 必应地图api文档,微软必应地图web开发版详解,可以在国内使用国外地图

    最近,公司项目要求在页面中嵌入地图,需求还算简单,但是由于必须具备响应式(主要是pc和移动端),而且由于公司业务是全球性的,要支持国外地点搜索.考虑到百度,腾讯,高德等等国内地图无法显示国外数据,谷歌 ...

  9. Microsoft Office 2016 简体中文 Vol 版镜像下载(Pro Plus、Visio、Project 下载)

    在使用上,零售版和批量授权版并没有区别,只是授权方式方面的区别,相对而言,VOL 版的更容易激活一些,其他并没有什么区别了. 有需要的可以在下面下载:(以下均是 VL 版) 版本:Office 201 ...

  10. CodeForces758D

    D. Ability To Convert time limit per test:1 second memory limit per test:256 megabytes input:standar ...