最近在做一个H5的项目,里边涉及到拍照上传图片的功能以及识别图片的功能,这里对识别图片的功能不做赘述,不属本文范畴。我在做完并上线项目后,同事跟我提了一个要求是可不可以同时选择多张图片上传,我做的时候的想法是如果给file表单加了 multiple 属性就没有办法调用手机的摄像头拍照了,如果不加,就无法同时选择多张图片,于是我就照实跟同事说了这个情况。但回头一想,单张图片可以上传,那多张图片呢?于是就有了本文的内容。

HTML5定义了 FileReader 作为文件 API 的重要成员用于读取文件,根据 W3C 的定义,FileReader接口提供了读取文件的方法和包含读取结果的事件模型。

FileReader的实例拥有 4 个方法,其中 3 个用以读取文件,另一个用来中断读取。下面的表格列出了这些方法以及他们的参数和功能,需要注意的是 ,无论读取成功或失败,方法并不会返回读取结果,这一结果存储在 result 属性中。

方法名 参数 描述
abort none 中断读取
readAsBinaryString file 将文件读取为二进制码
readAsDataURL file 将文件读取为 DataURL
readAsText file, [encoding] 将文件读取为文本

readAsText:该方法有两个参数,其中第二个参数是文本的编码方式,默认值为 UTF-8。这个方法非常容易理解,将文件以文本方式读取,读取的结果即是这个文本文件中的内容。

readAsBinaryString:该方法将文件读取为二进制字符串,通常我们将它传送到后端,后端可以通过这段字符串存储文件。

readAsDataURL:这是例子程序中用到的方法,该方法将文件读取为一段以 data: 开头的字符串,这段字符串的实质就是 Data URL,Data URL是一种将小文件直接嵌入文档的方案。这里的小文件通常是指图像与 html 等格式的文件。

FileReader还包含了一套完整的事件模型,用于捕获读取文件时的状态,下面这个表格归纳了这些事件。

事件 描述
onabort 中断时触发
onerror 出错时触发
onload 文件读取成功完成时触发
onloadend 读取完成触发,无论成功或失败
onloadstart 读取开始时触发
onprogress 读取中

文件一旦开始读取,无论成功或失败,实例的 result 属性都会被填充。如果读取失败,则 result 的值为 null ,否则即是读取的结果,绝大多数的程序都会在成功读取文件的时候,抓取这个值。

了解了H5提供的 FileReader 后,我们就使用 FileReader 来实现同事选择多张图片并上传。

首先,在 HTML 加入一个file表单,并设置其为 multiple(浏览器在对multiple、disabled、checked、selected等这类属性进行解析时,只要这些属性存在,默认的就会被解析成true,甭管你设置的是disabled=true或者disabled=false亦或是disabled="",如果不想这些属性起作用,唯有用js来remove掉这些属性,除非你不设置这些属性。),并设置accept="image/*"用以只能选择图片类型的文件,代码如下:

<input type="file"  accept="image/*" name="upload" id="upload" multiple>
<input type="hidden" id="hiddenImgUrl" /> <!--设置这个隐藏域是为了便于存放上传至服务器后返回的图片地址-->

接下来就到了js上场了:

//图片上传
var file = {
upload: function (e) {
var self = this;
var files = e.target.files;
var type = files[0].type.split('/')[0];
if (type != 'image') {
alertMsg('请上传图片');
return;
}
//var size = Math.floor(file.size / 1024 / 1024);
//if (size > 3) {
// alert('图片大小不得超过3M');
// return;
//};
for (var i = 0; i < files.length; i++) {
var reader = new FileReader();
reader.readAsDataURL(files[i]);
reader.onloadstart = function () {
//用以在上传前加入一些事件或效果,如载入中...的动画效果
};
reader.onloadend = function (e) {
var dataURL = this.result;
var imaged = new Image();
imaged.src = dataURL;
imaged.onload = function () { //利用canvas对图片进行压缩
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var w = 0;
var h = 0;
if (this.width > this.height) {
h = 1000;
var scale = this.width / this.height;
h = h > this.height ? this.height : h;
w = h * scale;
}
else {
w = 1000;
var scale = this.width / this.height;
w = w > this.width ? this.width : w
h = w / scale; } var anw = document.createAttribute("width");
var anh = document.createAttribute("height");
if (this.width > this.height) {
anw.value = h;
anh.value = w;
}
else {
anw.value = w;
anh.value = h;
}
canvas.setAttributeNode(anw);
canvas.setAttributeNode(anh); if (this.width > this.height) {
ctx.translate(h, 0);
ctx.rotate(90 * Math.PI / 180)
ctx.drawImage(this, 0, 0, w, h);
ctx.restore();
}
else {
ctx.drawImage(this, 0, 0, w, h);
}
dataURL = canvas.toDataURL('image/jpeg'); //回调函数用以向数据库提交数据
self.callback(dataURL);
};
};
}
},
event: function () {
$("#upload").change(function (e) {
file.upload(e);
});
},
callback: function (dataURL) {
$.ajaxSettings.async = false; //这里必须将ajax的异步改为同步才可以把返回并保存在隐藏域中的图片地址取出同时加在地址栏中作为参数一并传入下一个页面,这样做的目的是因为返回的图片地址不是一个json数组,而是单个的json字符串,所以只能将返回的图片地址json字符串拼接在一起作为参数传到下一个页面
$.post(url, dataURL, function (res) { //将base64图片流的图片通过后台转换成普通的图片路径并上传至服务器
var imgUrl = $("#hiddenImgUrl").val();
if (res.success) {
$(".loading").hide();
if (imgUrl != "") {
$("#hiddenImgUrl").val(imgUrl + "|" + res.imgUrl); //中间加一个 | 是为了到下一个页面便于将传过去的图片地址参数转换为数组
} else {
$("#hiddenImgUrl").val(res.imgUrl);
} var imgUrl = $("#hiddenImgUrl").val();
window.location.href = "apply.html?imgUrl=" + imgUrl; } else {
alert(res.message);
}
}, "json");
},
init: function () {
this.event();
}
}
file.init();

由于在通过post向服务器上传时采用了同步的方式,所以我在写项目的过程中,老是无法实现加载中的动画效果,并且把加载中的动画效果放在 reader.onloadstart方法中依旧不起作用,最后只能放在了$("#upload").change(function (e) {})方法中,代码如下:

 event: function () {
$("#upload").change(function (e) {
$(".loading").show();
file.upload(e);
});
}

以上是同时上传多张图片并将图片传入下一个页面继续进行后续操作,那么如何在同时上传完多张图片后在本页再预览这些图片呢?其实方法也是很简单的,上边callback函数里边的$.post的返回值里就包含了上传至服务器后的图片路径,将这些路径赋给img标签的src,然后再插入到页面中就OK了,代码如下:

callback: function (dataURL) {
$.post(url, dataURL, function (res) { //将base64图片流的图片通过后台转换成普通的图片路径并上传至服务器
if (res.success) {
$(".loading").hide();
var result = '<div class="result"><img src="'+res.imgUrl+'" alt=""/></div>';
var div = document.createElement('div');
div.innerHTML = result;
document.body.appendChild(div);
} else {
alert(res.message);
}
}, "json");
}

以上在预览图片时由于不需要跳转,不需要传入返回的所有图片的路径作为参数,所以也就不需要将ajax的异步设置为同步了。

js移动端/H5同时选择多张图片上传并使用canvas压缩图片的更多相关文章

  1. H5单张、多张图片上传

    前言 今天我们聊一聊图片上传,单张Or多张 ,如今,各大图片上传插件数不胜数,例如:Jquery的 verupload.js,jQuery File Upload.Uploadify.jQuery.f ...

  2. plupload 限制上传数量 只能选择一张图片上传

    var files=[];var errors=[];            var chunk=<%=request.getParameter("chunk")%>; ...

  3. 使用JCrop进行图片裁剪,裁剪js说明,裁剪预览,裁剪上传,裁剪设计的图片处理的工具类和代码

     1.要想制作图片裁剪功能,可以使用网上的裁剪工具JCrop,网址是:https://github.com/tapmodo/Jcrop/ 案例效果如下: 2.引入JCrop的js代码,具体要引入那 ...

  4. 用原生JS实现多张图片上传及预览功能(兼容IE8)

    最近需要做一个图片上传预览的功能(兼容IE8-11.chrome.firefox等浏览器),网上现有的文件上传组件(如webuploader)总是会遇到一些兼容性问题.于是我参考了一些博文(链接找不到 ...

  5. 前端提升生产力系列三(vant3 vue3 移动端H5下拉刷新,上拉加载组件的封装)

    | 在日常的移动端开发中,经常会遇到列表的展示,以及数据量变多的情况下还会有上拉和下拉的操作.进入新公司后发现移动端好多列表,但是在看代码的时候发现,每个列表都是单独的代码,没有任何的封装,都是通过v ...

  6. 微信小程序多张图片上传

    微信小程序上传图片每次只能上传一张,所有很多朋友就会问想要多张图片上传怎么办? 首先,我们来看一看wx.chooseImage(object)和wx.uploadFile(OBJECT)这两个个api ...

  7. nodejs-使用multer实现多张图片上传,express搭建脚手架

    nodejs-使用multer实现多张图片上传,express搭建脚手架 在工作中,我们经常会看到用户有多张图片上传,并且预览展示的需求.那么在具体实现中又该怎么做呢? 本实例需要nodejs基础,本 ...

  8. JavaScript实现多张图片上传功能

    今天闲着没事,把之前的多张图片上传代码整理了下. 页面主要代码: <div class="upBox upBox2"> <div class="d1&q ...

  9. 使用 jquery 的 上传文件插件 uploadify 3.1 配合 java 来做一个简单的文件上次功能。并且在界面上有radio 的选择内容也要上传

    使用 jquery 的 上传文件插件 uploadify 3.1 配合 java 来做一个简单的文件上次功能.并且在界面上有radio 的选择内容也要上传 uploadify 插件的 下载和文档地址  ...

随机推荐

  1. 机器学习笔记-1 Linear Regression(week 1)

    1.Linear Regression with One variable Linear Regression is supervised learning algorithm, Because th ...

  2. Unity 总裁 John Riccitiello 发话:VR足以匹敌互联网

    在2017年Vision Summit大会的开幕演讲中,Unity首席执行官John Riccitiello向观众通报了开发人员如何利用Oculus,HTC等品牌创造的机遇来打造虚拟现实(VR)行业, ...

  3. 运算符重载 与 sort()

    运算符重载与sort() 二话不说上代码: #include <iostream> #include <algorithm> using namespace std; stru ...

  4. Java数据类型(基本数据类型)学习

    Java数据类型(基本数据类型)学习 与其他语言一样,Java编程同样存在,比如int a,float b等.在学习变量之前我就必须先了解Java的数据类型啦. Java的数据类型包括基本数据类型和引 ...

  5. WebGIS开源解决方案之开发环境搭建(一)

    工欲善其事,必先利其器,本文主要讲述WebGIS开源解决方案之环境搭建--geoserver的安装 安装方式一:tomcat环境下安装 从tomcat官网下载tomcat环境,下载链接:http:// ...

  6. OC中的单例

    概念 单例模式的意图是类的对象称为系统中唯一的实例,提供一个访问点,供客户类共享资源 什么情况下使用单例 )类只能由一个实例,而且必须从一个为人熟知的访问点对其进行访问,比如工厂方法 )这个唯一的实例 ...

  7. JavaScript ,Python,java,C#,Go系列算法之【插入排序篇】

    常见的内部排序算法有:插入排序.希尔排序.选择排序.冒泡排序.归并排序.快速排序.堆排序.基数排序等.用一张图概括: 插入排序 插入排序(英语:Insertion Sort)是一种简单直观的排序算法. ...

  8. NancyFx 2.0的开源框架的使用-Stateless(二)

    继续上一篇Stateless的博文,在上一篇的博文的基础上稍微加点东西 接下来右键解决方案添加新项目,一样建一个空的Web项目 然后在StatelessDemoWeb项目里面添加Views文件夹,Sc ...

  9. Hibernate 核心接口和工作机制

    主要内容 Configuration类 sessionFactory接口 session接口 Transaction接口 Query 和 criteria接口 1.Configuration类 负责管 ...

  10. 用css3动画 @keyframes里设置transform:rotate(); 控制动画暂停和运动用属性:animation-play-state:paused暂停,在微信和safari里设置paused无效,在QQ里是正常的

    这几天遇到了两个很奇葩的问题,终于找到原因,趁还记得解决方法,赶紧记下来: 用css3动画 @keyframes里设置transform:rotate(); 控制动画暂停和运动可以用属性:animat ...