思路:先打開相冊,選取圖片,在剪切圖片,轉化爲base64格式,而後上傳到七牛存儲,返回url,再傳給後端,整個流程就是這樣。用的是angular框架,圖像插件用到imagecropper.js,廢話很少說,直接上代碼。javascript
效果:css
用到的插件html
<!DOCTYPE html> <html lang="en" ng-app=""> <head> <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no,width=device-width,height=device-height"/> <meta charset="UTF-8"> <title></title> <script type="text/javascript" src="app/lib/jquery.js"></script> <script type="text/javascript" src="app/lib/ionic/js/ionic.bundle.min.js"></script> <!-- 上傳頭像插件 --> <script src="app/lib/headimg/imagecropper.js"></script> <base href='/'/> </head> <body> <ion-nav-view> </ion-nav-view> <script type="text/javascript" src="app/dist/js/main-396e1d7cdb.js"></script> </body> </html>
頁面java
<ion-header-bar align-title="center" class="bar-light"> <button ui-sref="home.my" class="button button-clear"><i class="icon ion-ios-arrow-left"></i></button> <h1 class="title">我的資料</h1> </ion-header-bar> <ion-content class="my"> <ion-list> <ion-item class="item-input" style="height:1.1rem;" > <form id="form0" class="item-icon-right" href="javascript:void(0);" style="width: 100%"> <span class="input-label f26" style="margin-top:0.4rem; ">頭像</span> <i class="icon "><img ng-src="{{info.headimgurl||'app/dist/img/my/me_img.png'}}" style="width: 0.8rem;position: absolute;top: 0.1rem;right:0.7rem;border-radius:50%;border:3px solid rgba(0,0,0,0.3)" /></i> <!-- <form name="form0" id="form0" style="width: 100%"> --> <input type="file" name="file0" id="file0" multiple="multiple"><br> <!-- </form> --> <i class="icon "><img src="app/dist/img/my/arrow_icon.png" class="arrow_icon"></i> </form> </ion-item> </ion-list> </ion-content> <div class="img-container"> <img id="img0" src=""> <div class="close"><button class="button button-large button-light">取消</button></div> <div class="saveBtn" on-tap="save()"><button class="button button-large button-light" >選取</button></div> </div> <img class="newImg" src="">
cssjquery
.albumsbox { width: 18.9375rem; position: absolute; bottom: 0; left: 0.53125rem; display: none; z-index: 999; } .albumsbox .albums, .albumsbox .cancel { width: 100%; height: 6.1875rem; background: #fff; border-radius: 0.625rem; color: #333333; font-size: 0.8125rem; line-height: 3.0625rem; text-align: center; } .albumsbox .albums .line, .albumsbox .cancel .line { border-bottom: 1px solid #d1d1d4; } .albumsbox .cancel { height: 3.0625rem; margin: 0.34375rem 0rem 0.5625rem 0rem; } .container { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: none; background: #000; } .container #wrapper { width: 100%; height: 12.5rem; position: absolute; top: 40%; margin-top: -6.25rem; left: 0; } .container #wrapper #cropper { width: 100%; } .container #wrapper #previewContainer { display: none; } /*img prev*/ .img-container { width: 100%; height: 100%; position: absolute; top: 0; left: 0; display: none; background: #000; } .newImg { display: none; } .close { height: 1.1875rem; width: 30%; text-align: center; color: #fff; font-size: 0.8125rem; line-height: 1.1875rem; position: absolute; bottom: 1.5625rem; left: 0; } .saveBtn { height: 1.1875rem; width: 30%; text-align: center; color: #fff; font-size: 0.8125rem; line-height: 1.1875rem; position: absolute; bottom: 1.5625rem; right: 0; } .cropper-container { font-size: 0; line-height: 0; position: relative; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; direction: ltr !important; -ms-touch-action: none; touch-action: none; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; } .cropper-container img { display: block; width: 100%; min-width: 0 !important; max-width: none !important; height: 100%; min-height: 0 !important; max-height: none !important; image-orientation: 0deg !important; } .cropper-wrap-box, .cropper-canvas, .cropper-drag-box, .cropper-crop-box, .cropper-modal { position: absolute; top: 0; right: 0; bottom: 0; left: 0; } .cropper-wrap-box { overflow: hidden; } .cropper-drag-box { opacity: 0; background-color: #fff; filter: alpha(opacity=0); } .cropper-modal { opacity: .5; background-color: #000; filter: alpha(opacity=50); } .cropper-view-box { display: block; overflow: hidden; width: 100%; height: 100%; outline: 1px solid #39f; outline-color: rgba(51, 153, 255, 0.75); } .cropper-dashed { position: absolute; display: block; opacity: .5; border: 0 dashed #eee; filter: alpha(opacity=50); } .cropper-dashed.dashed-h { top: 33.33333%; left: 0; width: 100%; height: 33.33333%; border-top-width: 1px; border-bottom-width: 1px; } .cropper-dashed.dashed-v { top: 0; left: 33.33333%; width: 33.33333%; height: 100%; border-right-width: 1px; border-left-width: 1px; } .cropper-center { position: absolute; top: 50%; left: 50%; display: block; width: 0; height: 0; opacity: .75; filter: alpha(opacity=75); } .cropper-center:before, .cropper-center:after { position: absolute; display: block; content: ' '; background-color: #eee; } .cropper-center:before { top: 0; left: -3px; width: 7px; height: 1px; } .cropper-center:after { top: -3px; left: 0; width: 1px; height: 7px; } .cropper-face, .cropper-line, .cropper-point { position: absolute; display: block; width: 100%; height: 100%; opacity: .1; filter: alpha(opacity=10); } .cropper-face { top: 0; left: 0; background-color: #fff; } .cropper-line { background-color: #39f; } .cropper-line.line-e { top: 0; right: -3px; width: 5px; cursor: e-resize; } .cropper-line.line-n { top: -3px; left: 0; height: 5px; cursor: n-resize; } .cropper-line.line-w { top: 0; left: -3px; width: 5px; cursor: w-resize; } .cropper-line.line-s { bottom: -3px; left: 0; height: 5px; cursor: s-resize; } .cropper-point { width: 5px; height: 5px; opacity: .75; background-color: #39f; filter: alpha(opacity=75); } .cropper-point.point-e { top: 50%; right: -3px; margin-top: -3px; cursor: e-resize; } .cropper-point.point-n { top: -3px; left: 50%; margin-left: -3px; cursor: n-resize; } .cropper-point.point-w { top: 50%; left: -3px; margin-top: -3px; cursor: w-resize; } .cropper-point.point-s { bottom: -3px; left: 50%; margin-left: -3px; cursor: s-resize; } .cropper-point.point-ne { top: -3px; right: -3px; cursor: ne-resize; } .cropper-point.point-nw { top: -3px; left: -3px; cursor: nw-resize; } .cropper-point.point-sw { bottom: -3px; left: -3px; cursor: sw-resize; } .cropper-point.point-se { right: -3px; bottom: -3px; width: 20px; height: 20px; cursor: se-resize; opacity: 1; filter: alpha(opacity=100); } .cropper-point.point-se:before { position: absolute; right: -50%; bottom: -50%; display: block; width: 200%; height: 200%; content: ' '; opacity: 0; background-color: #39f; filter: alpha(opacity=0); } @media (min-width: 768px) { .cropper-point.point-se { width: 15px; height: 15px; } } @media (min-width: 992px) { .cropper-point.point-se { width: 10px; height: 10px; } } @media (min-width: 1200px) { .cropper-point.point-se { width: 5px; height: 5px; opacity: .75; filter: alpha(opacity=75); } } .cropper-invisible { opacity: 0; filter: alpha(opacity=0); } .cropper-hide { position: absolute; display: block; width: 0; height: 0; } .cropper-hidden { display: none !important; } .cropper-move { cursor: move; }
jsios
/** * laoyou Module * * Description */ angular.module('app').controller('myEditCtrl', ['$scope', 'api', '$rootScope', '$http', '$state', '$stateParams','$ionicModal','qiniuConfig', function($scope, api, $rootScope, $http, $state, $stateParams,$ionicModal,qiniuConfig) { var showLoad = $rootScope.showLoad; $http.post("member/info",{test:1}).success(function(data){ $scope.info=data.data; if(!$scope.info.birthday){ $scope.info.birthday=new Date("1951-01-01"); }else{ $scope.info.birthday=new Date($scope.info.birthday); } }).error(function(){ $rootScope.loadFn.hide(); }); var config=angular.copy(qiniuConfig); // console.log(config) if(config){ var token=config.UpToken; } /*picBase是base64圖片帶頭部的完整編碼*/ function putb64(picBase){ /*picUrl用來存儲返回來的url*/ var picUrl; /*把頭部的data:image/png;base64,去掉。(注意:base64後面的逗號也去掉)*/ picBase=picBase.substring(22); /*經過base64編碼字符流計算文件流大小函數*/ function fileSize(str) { var fileSize; if(str.indexOf('=')>0) { var indexOf=str.indexOf('='); str=str.substring(0,indexOf);//把末尾的’=‘號去掉 } fileSize=parseInt(str.length-(str.length/8)*2); return fileSize; } /*把字符串轉換成json*/ function strToJson(str) { var json = eval('(' + str + ')'); return json; } var url = "http://up.qiniu.com/putb64/"+fileSize(picBase); var xhr = new XMLHttpRequest(); xhr.onreadystatechange=function() { if (xhr.readyState==4){ var keyText=xhr.responseText; // alert(keyText) /*返回的key是字符串,須要裝換成json*/ keyText=strToJson(keyText); /* http://ojvh6i96g.bkt.clouddn.com/是個人七牛雲空間網址,keyText.key 是返回的圖片文件名*/ picUrl=config.recordPath+'/'+keyText.key; // alert(picUrl); $http.post("member/updateHead",{headimgurl:picUrl}).success(function (res) { if( res.statusCode == 0) { window.location.reload(); }else{ alert("修改失敗"); } }).error(function(data){ alert("網絡異常") }); } } xhr.open("POST", url, true); xhr.setRequestHeader("Content-Type", "application/octet-stream"); xhr.setRequestHeader("Authorization", "UpToken "+ token); //token換成本身申請七牛的。 xhr.send(picBase); } // var _czc = []; $("#file0").change(function(){ // _czc.push(["_trackEvent", "我的資料頁","頭像",""]); // console.log($("#img0")) var objUrl = getObjectURL(this.files[0]) ; console.log("objUrl = "+objUrl) ; if (objUrl) { $("#img0").attr("src", objUrl) ; $('.cropper-canvas img').attr('src',objUrl); $('.cropper-view-box img').attr('src',objUrl); } var File=$('#img0').attr('src'); if(File!=''||File==undefined){ // $scope.openModal(); $(".my").css('opacity','0'); $('.img-container').show(); } }) ; //創建一個可存取到該file的url function getObjectURL(file) { console.log(file) var url = null ; if (window.createObjectURL!=undefined) { // basic url = window.createObjectURL(file) ; } else if (window.URL!=undefined) { // mozilla(firefox) url = window.URL.createObjectURL(file) ; } else if (window.webkitURL!=undefined) { // webkit or chrome url = window.webkitURL.createObjectURL(file) ; } return url ; } $('.close').click(function(){ $(".my").css('opacity','1'); $('.img-container').hide(); }) function convertToData(url, canvasdata, cropdata, callback) { var cropw = cropdata.width; // 剪切的寬 var croph = cropdata.height; // 剪切的寬 var imgw = canvasdata.width; // 圖片縮放或則放大後的高 var imgh = canvasdata.height; // 圖片縮放或則放大後的高 var poleft = canvasdata.left - cropdata.left; // canvas定位圖片的左邊位置 var potop = canvasdata.top - cropdata.top; // canvas定位圖片的上邊位置 var canvas = document.createElement("canvas"); var ctx = canvas.getContext('2d'); canvas.width = cropw; canvas.height = croph; var img = new Image(); img.src = url; img.onload = function() { this.width = imgw; this.height = imgh; // 這裏主要是懂得canvas與圖片的裁剪之間的關係位置 ctx.drawImage(this, poleft, potop, this.width, this.height); var base64 = canvas.toDataURL('image/jpg', 1); // 這裏的「1」是指的是處理圖片的清晰度(0-1)之間,固然越小圖片越模糊,處理後的圖片大小也就越小 callback && callback(base64) // 回調base64字符串 } } $(function(){ var $image = $('.img-container > img'); $image.on("load", function() { // 等待圖片加載成功後,才進行圖片的裁剪功能 $image.cropper({ aspectRatio: 1 / 1 // 1:1的比例進行裁剪,能夠是任意比例,本身調整 }); }) // 點擊保存 // $(".saveBtn").on("click", function() { $scope.save = function(){ var src = $image.eq(0).attr("src"); var canvasdata = $image.cropper("getCanvasData"); var cropBoxData = $image.cropper('getCropBoxData'); convertToData(src, canvasdata, cropBoxData, function(basechar) { // 回調後的函數處理 $(".newImg").attr("src", basechar); // alert(basechar) putb64(basechar); }); } }) }]);
其中qiniuConfig是本身向後臺要的,這是上傳圖片的身份憑證,這是個人qiniuConfig。web
這是我頭像上傳頁面的路由。chrome
若有什麼問題,歡迎指正。json