功能需求:
实现本地图片裁剪功能,要求裁剪得到的图片像素在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 }
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的运用,再结合实际的项目需求理清逻辑,按照需求实现功能。
最后:
从实习到正式,进入前端开发工作将近两年了,最近在项目开发中遇到一些问题,其实是以前曾经遇到过的,但是却不能很清晰记起以前是如何解决的,导致还要再去重新搜索回顾,解决问题的效率大大变慢。
于是觉得总结和思考,这项区别人与人之间能力差距的一个重要因素,更应该去重视和锻炼。
希望自己不要懒惰。