JS移动端/H5同时选择多张图片上传并使用canvas压缩图片


Posted in Javascript onJune 20, 2017

最近在做一个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压缩图片,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
Javascript 函数对象的多重身份
Jun 28 Javascript
Javascript string 扩展库代码
Apr 09 Javascript
基于jquery用于查询操作的实现代码
May 10 Javascript
单击和双击事件的冲突处理示例代码
Apr 03 Javascript
jQuery选择器之基本选择器与层次选择器
Mar 03 Javascript
JS实现灵巧的下拉导航效果代码
Aug 25 Javascript
微信小程序 switch组件详解及简单实例
Jan 10 Javascript
Angular2生命周期钩子函数的详细介绍
Jul 10 Javascript
分享Bootstrap简单表格、表单、登录页面
Aug 04 Javascript
vuex学习之Actions的用法详解
Aug 29 Javascript
如何在微信小程序里面退出小程序的方法
Apr 28 Javascript
scrapyd schedule.json setting 传入多个值问题
Aug 07 Javascript
BootStrap Select清除选中的状态恢复默认状态
Jun 20 #Javascript
Vue实现路由跳转和嵌套
Jun 20 #Javascript
Vue.2.0.5实现Class 与 Style 绑定的实例
Jun 20 #Javascript
JS中的三个循环小结
Jun 20 #Javascript
详解Vue 方法与事件处理器
Jun 20 #Javascript
Vue Ajax跨域请求实例详解
Jun 20 #Javascript
详解webpack 入门总结和实践(按需异步加载,css单独打包,生成多个入口文件)
Jun 20 #Javascript
You might like
PHP中的类型提示(type hinting)功能介绍
2015/07/01 PHP
如何在标题栏显示框架内页面的标题
2007/02/03 Javascript
javascript椭圆旋转相册实现代码
2012/01/16 Javascript
JS画5角星方法介绍
2013/09/17 Javascript
js跨域访问示例(客户端/服务端)
2014/05/19 Javascript
浅析2种JavaScript继承方式
2015/12/04 Javascript
浅析Bootstrap表格的使用
2016/06/23 Javascript
几句话带你理解JS中的this、闭包、原型链
2016/09/26 Javascript
javascript简单进制转换实现方法
2016/11/24 Javascript
JavaScript Base64 作为文件上传的实例代码解析
2017/02/14 Javascript
探索webpack模块及webpack3新特性
2017/09/18 Javascript
微信小程序实现添加手机联系人功能示例
2017/11/30 Javascript
Vue-cli Eslint在vscode里代码自动格式化的方法
2018/02/23 Javascript
详解浏览器缓存和webpack缓存配置
2018/07/06 Javascript
Vue实现动态添加或者删除对象和对象数组的操作方法
2018/09/21 Javascript
jQuery访问json文件中数据的方法示例
2019/01/28 jQuery
详解JavaScript 的变量
2019/03/08 Javascript
简单了解JavaScript中常见的反模式
2019/06/21 Javascript
python两种遍历字典(dict)的方法比较
2014/05/29 Python
Python使用metaclass实现Singleton模式的方法
2015/05/05 Python
python数据清洗系列之字符串处理详解
2017/02/12 Python
详解Tensorflow数据读取有三种方式(next_batch)
2018/02/01 Python
python对csv文件追加写入列的方法
2019/08/01 Python
python中resample函数实现重采样和降采样代码
2020/02/25 Python
详解pycharm连接远程linux服务器的虚拟环境的方法
2020/11/13 Python
关于Python错误重试方法总结
2021/01/03 Python
HTML5 SEO优化的一些建议
2020/08/27 HTML / CSS
Alba Moda瑞士网上商店:独家意大利时尚女装销售
2016/11/28 全球购物
英国优质鞋类专家:Robinson’s Shoes
2017/12/08 全球购物
俄罗斯皮肤健康中心:Pharmacosmetica.ru
2020/02/22 全球购物
体育教师工作总结的自我评价
2013/10/10 职场文书
银行业务授权委托书
2014/10/10 职场文书
四风问题专项整治工作情况报告
2014/10/28 职场文书
社区低保工作总结2015
2015/07/23 职场文书
会议开幕致辞怎么写
2016/03/03 职场文书
使用 Docker Compose 构建复杂的多容器App
2022/04/30 Servers