首页 > 代码库 > html5,js插件实现手机端实现头像剪切上传

html5,js插件实现手机端实现头像剪切上传

思路:先打开相册,选取图片,在剪切图片,转化为base64格式,然后上传到七牛存储,返回url,再传给后端,整个流程就是这样。用的是angular框架,图像插件用到imagecropper.js,废话不多说,直接上代码。

效果:

技术分享

技术分享

技术分享

 

 

用到的插件

<!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="http://www.mamicode.com/app/lib/jquery.js"></script>
	
	<script type="text/javascript" src="http://www.mamicode.com/app/lib/ionic/js/ionic.bundle.min.js"></script>

	<!-- 上传头像插件 -->
	
	<script src="http://www.mamicode.com/app/lib/headimg/imagecropper.js"></script>
	
	<base href=http://www.mamicode.com/‘/‘/>"text/javascript" src="http://www.mamicode.com/app/dist/js/main-396e1d7cdb.js"></script>

</body>
</html>	

 

页面

<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="">

 

css

.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; }

js

/**
 * 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 = http://www.mamicode.com/$image.eq(0).attr("src");  
          var canvasdata = http://www.mamicode.com/$image.cropper("getCanvasData");  
          var cropBoxData = http://www.mamicode.com/$image.cropper(‘getCropBoxData‘);  
          convertToData(src, canvasdata, cropBoxData, function(basechar) {
              // 回调后的函数处理  
              $(".newImg").attr("src", basechar);
              // alert(basechar)
              putb64(basechar);
              
          });
      }
    })

}]);

 其中qiniuConfig是自己向后台要的,这是上传图片的身份凭证,这是我的qiniuConfig。

技术分享

 

这是我头像上传页面的路由。

 技术分享

 

 

 

如有什么问题,欢迎指正。

html5,js插件实现手机端实现头像剪切上传