纯前端实现本地图片裁剪上传功能(Cropper & Web Uploader结合使用)

功能需求:

实现本地图片裁剪功能,要求裁剪得到的图片像素在420-1500px之间,不大于2M,并将裁剪后图片传给后台

使用插件:

Cropper(项目地址:https://github.com/fengyuanchen/cropper)实现裁剪

Web Uploader(项目地址:https://github.com/fex-team/webuploader)实现图片上传

功能实现:

1.HTML

1 <div>
2     <div class="up-pick">
3         <a href="javascript:void(0)" id="picker">上传图片</a>
4     </div>
5     <input type="file" class="fileInput" hidden />
6 </div>

 

2.CSS

引入cropper.css文件

 

3.JS

由于cropper依赖于jQuery,这里引入jQuery,cropper.js和webuploader.js

1 // 触发input file
2 $("#picker").on('click', function () {
3     $(this).parents(".up-pick").siblings(".fileInput").trigger("click");
4 });

编写input file change事件

  1 $(".fileInput").on('change', function() {
  2     var file = this.files[0]; //获取上传图片,IE有兼容性问题
  3 
  4     //检测图片格式和大小的合理性,在这里为了简便,用console.log。实际项目中可用Dialog组件做弹窗提示
  5     if(!(file.type == 'image/jpeg' || file.type == 'image/jpg' || file.type == 'image/gif' || file.type == 'image/png')) {
  6         console.log('支持图片格式:GIF、JPG、JPEG、PNG');
  7         $(".fileInput").val('');
  8         return;
  9     }else if(file.size > 2097152) {
 10         console.log('图片大小不超过2M'),
 11         $(".fileInput").val('');//这里若不清空,再次传入同一张图片,input file的change事件不会触发
 12         return;
 13     }
 14 
 15     // 初始化WebUploader
 16     var uploader = WebUploader.create({
 17         auto: true,// 选完文件后,是否自动上传。
 18         server: '/Image/productImageUploader',// 文件接收服务端。
 19         fileSingleSizeLimit: 2 * 1024 * 1024,
 20         duplicate: true,
 21         accept: {// 只允许选择图片文件。
 22             title: 'Images',
 23             extensions: 'jpg,jpeg,png',
 24             mimeTypes: 'image/jpg,image/jpeg,image/png'
 25         }
 26     });
 27 
 28     var image; //上传的图片
 29     var cropper; //cropper对象
 30     var reader = new FileReader();  
 31 
 32    reader.onload = function() {
 33         var url = reader.result;
 34         var cropperImg = new Image(); //这步操作是为了拿到图片的尺寸
 35         cropperImg.src = url;
 36                 
 37         cropperImg.onload = function() {
 38             if(this.width < 420 || this.height < 420){ 
 39                 console.log('图片尺寸应大于420*420像素');
 40                 $(".fileInput").val('')
 41                 return;
 42             }
 43 
 44             //所有检测通过,弹出弹窗,在弹窗中进行图片裁剪操作
 45             new Dialog({
 46                title: "裁剪图片",
 47                content: '<div class="modifyBg"><div class="imgWrapper"><img id="image" src="' + url + '"></div></div>',
 48                button: [{
 49                     value: '确定',
 50                     callback: function () {
 51                     var type = $(image).attr('src').split(';')[0].split(':')[1];//得出图片格式:类似image/jpeg
 52                     var canVas = cropper.getCroppedCanvas();//获取裁剪后得到的canvas数据
 53                     var file = convertBase64UrlToBlob(canVas.toDataURL('image/jpeg','0.0'));//将canvas转换为Blob格式
 54                     uploader.addFiles(file);//将裁剪后的图片添加进webuploader上传到后台
 55                     this.close();
 56                 }
 57             }, {
 58                  value: '取消',
 59                  callback: function () {
 60                        $(".fileInput").val('')
 61                        this.close();
 62                  }
 63              }]
 64          }).show(); 
 65 
 66          // 图片上传
 67          image = document.querySelector('#image');
 68          cropper = new Cropper(image, {
 69              viewMode: 1, //裁剪框只能在图片范围内移动
 70              dragMode: 'move', //图片可以拖动
 71              aspectRatio: 1, //裁剪比例,NaN-自由选择区域
 72              zoomable: false, //禁止缩放,在控制裁剪像素,允许缩放会有问题
 73              ready: function() {
 74                cropper.setData({//初始裁剪区域占图片比例
 75                   width: 420,
 76                     height: 420
 77                 })
 78              },
 79              cropmove: function() {
 80                   var data = cropper.getData()
 81                   if(data.width > 1500 || data.height > 1500) {
 82                     cropper.setData({
 83                          width: 1500,
 84                           height: 1500
 85                       })
 86                   }
 87                   if(data.width < 420 || data.height < 420) {
 88                       cropper.setData({
 89                           width: 420,
 90                           height: 420
 91                       })
 92                   }
 93               }
 94           });
 95       }; 
 96    }
 97    reader.readAsDataURL(file);//File对象转换为dataURL  
 98 
 99    uploader.on('uploadSuccess', function(file, rs) {
100     // 图片上传回调函数
101    });
102 
103    uploader.on('startUpload', function(file, rs) {
104       console.log("文件正在上传中,请稍候");
105    });
106 }                                                        
将以base64的图片url数据转换为Blob用webuploader上传给后台
 1 function convertBase64UrlToBlob(urlData){
 2     var bytes=window.atob(urlData.split(',')[1]);//去掉url的头,并转换为byte
 3       
 4     //处理异常,将ascii码小于0的转换为大于0
 5     var ab = new ArrayBuffer(bytes.length);
 6     var ia = new Uint8Array(ab);
 7     for (var i = 0; i < bytes.length; i++) {
 8          ia[i] = bytes.charCodeAt(i);
 9     }
10 
11     return new Blob( [ab] , {type : 'image/jpeg'});
12  }    

 

列几个这里踩到的坑:

①图片裁剪前限制2M,但出现裁剪后图片大于2M的情况:

    发现canVas.toDataURL方法接收两个参数,不传的话默认转为image/png格式,图片质量为1.0。这样就导致了裁剪后得到的图片大大大于原始图片。

    查文档看到

    如果type参数的值为image/jpeg或image/webp,则第二个参数的值如果在0.0和1.0之间的话,会被看作是图片质量参数,如果第二个参数的值不在0.0和1.0之间,则会使用默认的图片质量.

 于是我这里修改为 canVas.toDataURL('image/jpeg','0.0')

 

②由于技术栈使用webuploader结合cropper实现裁剪上传,这里我用了input file,整个的逻辑就是

 通过change事件对图片格式和大小做合理性检验 → 通过H5中FileReader获取图片base64格式url → 再结合new Image()拿到图片尺寸,对图片尺寸做检验 → 进入裁剪阶段通过cropper.ready方法初始化裁剪框为图片像素420的大小,裁剪过程cropmove方法实时控制裁剪框的最大最小尺寸 → cropper.getCroppedCanvas获取裁剪后得到的canvas数据 → canVas.toDataURL转为base64格式 → 自定义convertBase64UrlToBlob方法将base64转为blob图片格式 → webuploader.addFiles方法上传最终的图片

 

③其实整个图片裁剪上传的过程并不难,主要是两个插件以及H5的API的运用,再结合实际的项目需求理清逻辑,按照需求实现功能。

 

最后:

从实习到正式,进入前端开发工作将近两年了,最近在项目开发中遇到一些问题,其实是以前曾经遇到过的,但是却不能很清晰记起以前是如何解决的,导致还要再去重新搜索回顾,解决问题的效率大大变慢。

于是觉得总结和思考,这项区别人与人之间能力差距的一个重要因素,更应该去重视和锻炼。

希望自己不要懒惰。

 

posted @ 2017-08-07 16:16  zhwaner  阅读(2886)  评论(1编辑  收藏  举报