1. 程式人生 > >H5學習之路-圖片上傳(cropper、webuploader)

H5學習之路-圖片上傳(cropper、webuploader)

好久沒有寫部落格了,感覺都不習慣了。一方面是因為工作佔用的時間過多,另一方面是自己有點懶,沒有堅持。好了,少扯這些沒用的東西,直入主題唄。

筆者目前在公司會接觸到H5的開發,也就是手機端app的開發,但是用的H5,而非原生的方式,主要是節省開發時間,不必針對android或者ios各自單獨開發一套。但是,H5的方式因為各個系統、不同版本之間也會存在一些相容性的問題,所以選擇一些合適的外掛,也是至關重要,特別是相容性方面的處理。

圖片上傳,這個功能相信很多童鞋都會用到,但是在手機端就得注意一些相容性的問題,比如在ios上就存在圖片旋轉的bug,再就是要考慮圖片的壓縮、裁剪、旋轉、 等問題。今天,筆者就給大家介紹兩個外掛cropper和webuploader。cropper是一款使用簡單且功能強大的圖片剪裁jQuery外掛。該圖片剪裁外掛支援圖片放大縮小,支援圖片旋轉,支援觸控式螢幕裝置,支援canvas,並且支援跨瀏覽器使用。而WebUploader是由Baidu WebFE(FEX)團隊開發的一個簡單的以HTML5為主,FLASH為輔的現代檔案上傳元件。如果你的H5專案是基於zepto.js,你就可以使用webuploader這個外掛;如果你的H5專案是基於jquery,你就可以使用cropper這個外掛。webuploader是相容zepto和jquery的,而cropper只能基於jquery。

下面,提供下這兩個外掛的學習地址:

一、外掛目錄結構介紹

筆者這個例子的目錄結構以及所需外掛,截圖如下:
這裡寫圖片描述

二、cropper圖片上傳

頁面imageUpload1.html:

<!DOCTYPE html>
<html>
<head>
  <title>cropper圖片上傳</title>
  <meta charset="utf-8"/>
  <link rel="stylesheet" href="/m/plugins/cropper/cropper.min.css" />
</head>
<body> <input id="btn1" type="file" accept="image/*,camera" capture="camera" style="opacity: 0;"/> <div> <button id="upload_btn" >上傳頭像</button> <button id="image_save" >儲存</button> <img id="face_image" style="width:50px;height:50px;border-radius: 25px;border: 1px solid #fff;"
/>
</div> <div class="upload-img" style="width:100%;height: 100%;"> <img src=""/> </div> <script src="/m/plugins/jquery/jquery-1.12.2.js" type="text/javascript"></script> <script src="/m/plugins/cropper/cropper.min.js" type="text/javascript"></script> <script src="/m/plugins/cropper/canvas-toBlob.js" type="text/javascript"></script> <script src="../../scripts/imageUpload/imageUpload1.js" type="text/javascript"></script> </body> </html>

js imageUpload1.js:

/**
 * cropper圖片上傳
 */
$(function() {
  console.log('cropper圖片上傳。。。');

  //觸發input file
  $('#upload_btn').click(function() {
    console.log('模擬點選。。。');
    $('#btn1').trigger('click');
  });

  //圖片上傳
  var $image = $('.upload-img > img');
  $image.cropper({
      viewMode: 1,
//      preview: '.img-preview', //不同尺寸預覽區
      aspectRatio: 1, //裁剪比例,NaN-自由選擇區域
      autoCropArea: 0.7, //初始裁剪區域佔圖片比例
      crop: function(data) { //裁剪操作回撥
      }
  });
  var fileName; //選擇上傳的檔名
  $('#btn1').change(function(){
      var file = this.files[0];
      fileName = file.name;
      var reader = new FileReader();
      //reader回撥,重新初始裁剪區
      reader.onload = function(){
          // 通過 reader.result 來訪問生成的 DataURL
          var url = reader.result;
          //選擇圖片後重新初始裁剪區
          $image.cropper('reset', true).cropper('replace', url);
      };
      reader.readAsDataURL(file);
  });

  /*
   * 上傳圖片
   */
  $('#image_save').click(function() {
      var type = $image.attr('src').split(';')[0].split(':')[1];

      var canVas = $image.cropper("getCroppedCanvas", {});
      //將裁剪的圖片載入到face_image
      $('#face_image').attr('src', canVas.toDataURL());
      canVas.toBlob(function(blob) {
          var formData = new FormData();
          formData.append("file", blob, fileName);

          $.ajax({
              type: "POST",
              url: '/sys/file/uploadImage.do',
              data: formData,
              contentType: false, //必須
              processData: false, //必須
              dataType: "json",
              success: function(retJson){
                  //清空上傳檔案的值
                  $('#btn1').val('');

                  //上傳成功
                  console.log('retJson:', retJson);
              },
              error : function() {
                  //清空上傳檔案的值
                  $(_pageId + '#btn1').val('');
              }
          });
      }, type);
  });

  //取消
  $("#image_cancel").click(function() {
    //清空上傳檔案的值
    $(_pageId + inputFileId).val('');
  });
});

效果圖如下:
這裡寫圖片描述

三、WebUploader圖片上傳

頁面imageUpload2.html:

<!DOCTYPE html>
<html>
<head>
  <title>webuploader圖片上傳</title>
  <meta charset="utf-8"/>
  <link rel="stylesheet" href="/m/plugins/webuploder/webuploader.css" />
</head>
<body>

<img id="face_image" style="width:50px;height:50px;border-radius: 25px;border: 1px solid #fff;"/>

<div id="uploader-demo">
  <div id="fileList" class="uploader-list"></div>
  <div id="filePicker">選擇圖片</div>
</div>

<script src="/m/plugins/zepto/zepto.min.js" type="text/javascript"></script>
<script src="/m/plugins/webuploder/webuploader.html5only.min.js" type="text/javascript"></script>
<script src="../../scripts/imageUpload/imageUpload2.js" type="text/javascript"></script>
</body>
</html>

js imageUpload2.js:

/**
 * webuploader圖片上傳
 */
$(function() {
  console.log('webuploader圖片上傳。。。');

  var webuploaderutil = {};
  // Web Uploader例項
  var uploader;

  var $list = $('#fileList'),
  // 優化retina, 在retina下這個值是2
  ratio = window.devicePixelRatio || 1,
  thumbnailWidth = 100 * ratio, thumbnailHeight = 100 * ratio,

  // 初始化Web Uploader
  uploader = WebUploader.create({
    // 自動上傳。
    auto : true,
    // 檔案接收服務端。
    server : '/sys/file/uploadImage.do',
    // 選擇檔案的按鈕。可選。
    // 內部根據當前執行是建立,可能是input元素,也可能是flash.
    pick : '#filePicker',
    // 只允許選擇檔案,可選。
    accept : {
      title : 'Images',
      extensions : 'gif,jpg,jpeg,bmp,png',
      mimeTypes : 'image/*'
    }
  });

  // 當有檔案新增進來的時候
  uploader.on('fileQueued', function(file) {
     var $li = $('<div id="' + file.id + '" class="file-item thumbnail">'
        + '<img>' + '<div class="info">' + file.name + '</div>'
        + '</div>'), $img = $li.find('img');

     $list.append($li);

    // 建立縮圖
    uploader.makeThumb(file, function(error, src) {
      if (error) {
        $("#face_image").replaceWith('<span>不能預覽</span>');
        $img.attr( 'src', src );
        return;
      }

      $img.attr( 'src', src );
      $("#face_image").attr('src', src);
    }, thumbnailWidth, thumbnailHeight);

  });

  // 檔案上傳過程中建立進度條實時顯示。
  uploader.on('uploadProgress', function(file, percentage) {
    var $li = $( '#'+file.id ),
    $percent = $li.find('.progress span');

    // 避免重複建立
    if ( !$percent.length ) {
        $percent = $('<p class="progress"><span></span></p>')
                .appendTo( $li )
                .find('span');
    }

    $percent.css( 'width', percentage * 100 + '%' );
  });

  // 檔案上傳成功,給item新增成功class, 用樣式標記上傳成功。
  uploader.on('uploadSuccess', function(file, response) {
    $('#' + file.id).addClass('upload-state-done');

    //重新初始化
//    webuploaderutil.uploadPicByResp(uploadDiv, imgEle, success, error);
    console.log('response:', response);
  });

  // 檔案上傳失敗,現實上傳出錯。
  uploader.on('uploadError', function(file) {
    var $li = $('#' + file.id), $error = $li.find('div.error');

    // 避免重複建立
    if (!$error.length) {
      $error = $('<div class="error"></div>').appendTo($li);
    }

    $error.text('上傳失敗');
  });

  // 完成上傳完了,成功或者失敗,先刪除進度條。
  uploader.on('uploadComplete', function(file) {
    $('#' + file.id).find('.progress').remove();
  });
});

效果圖如下:
這裡寫圖片描述

四、後臺sevlet請求圖片處理

因為筆者搭的是springMVC的框架,所以提供的程式碼寫法就是SpringMVC的寫法,大家也可以用sevlet,這個沒什麼區別,程式碼如下:

/**
 * Project Name:qyk_testSpringMVC
 * File Name:FileController.java
 * Package Name:com.qiyongkang.sys.controller
 * Date:2016年11月6日下午3:12:05
 * Copyright (c) 2016, Thinkive(http://www.thinkive.com/) All Rights Reserved.
 *
*/

package com.qiyongkang.sys.controller;

import java.io.File;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.qiyongkang.sys.dto.ExtJsObject;

/**
 * ClassName:FileController <br/>
 * Function: TODO ADD FUNCTION. <br/>
 * Reason: TODO ADD REASON. <br/>
 * Date: 2016年11月6日 下午3:12:05 <br/>
 * 
 * @author qiyongkang
 * @version
 * @since JDK 1.6
 * @see
 */
@Controller
@RequestMapping
public class FileController {
    /**
     * 日誌類
     */
    private static Logger log = LogManager.getLogger(FileController.class);

    private String tempPath = "/uploadImageTemp";// 臨時儲存目錄

    private String savePath = "/userImage";// 儲存目錄

    private String fileName = ""; // 檔名

    @RequestMapping
    @ResponseBody
    public ExtJsObject uploadImage(HttpServletRequest request) {
        ExtJsObject extJsObject = new ExtJsObject();
        try {
            // 獲取臨時目錄
            String tempPathDir = request.getSession().getServletContext().getRealPath(this.tempPath);
            File tempPathDirFile = new File(tempPathDir);
            if (!tempPathDirFile.exists()) {
                tempPathDirFile.mkdirs();
            }

            // 儲存目錄
            String realDir = request.getSession().getServletContext().getRealPath(this.savePath);
            File realDirFile = new File(realDir);
            if (!realDirFile.exists()) {
                realDirFile.mkdirs();
            }

            // Create a factory for disk-based file items
            DiskFileItemFactory factory = new DiskFileItemFactory();

            // Set factory constraints
            factory.setSizeThreshold(4096); // 設定緩衝區大小,這裡是4kb
            factory.setRepository(tempPathDirFile);// 設定緩衝區目錄

            // Create a new file upload handler
            ServletFileUpload upload = new ServletFileUpload(factory);

            // Set overall request size constraint
            upload.setSizeMax(4194304); // 設定最大檔案尺寸,這裡是4MB

            List<FileItem> items = upload.parseRequest(request);// 得到所有的檔案
            Iterator<FileItem> i = items.iterator();
            if (i.hasNext()) {
                FileItem fi = (FileItem) i.next();
                String fileName = fi.getName();
                if (fileName != null) {
                    // 這裡加一個限制,如果不是圖片格式,則提示錯誤. (gif,jpg,jpeg,bmp,png)
                    String suffixName = FilenameUtils.getExtension(fileName);
                    if ("gif".equalsIgnoreCase(suffixName) || "jpg".equalsIgnoreCase(suffixName)
                            || "jpeg".equalsIgnoreCase(suffixName) || "bmp".equalsIgnoreCase(suffixName)
                            || "png".equalsIgnoreCase(suffixName)) {
                        // 檔名
                        this.fileName = new Date().getTime() + "." + FilenameUtils.getExtension(fileName);
                        File savedFile = new File(realDir, this.fileName);
                        fi.write(savedFile);
                        // 小圖片
                        File savedSmallFile = new File(realDir + "/small/", this.fileName);
                        FileUtils.copyFile(savedFile, savedSmallFile);
                    } else {
                        extJsObject.setSuccess(false);
                        extJsObject.setMsg("非圖片格式,請重新上傳!");
                    }
                }
            }

            extJsObject.setSuccess(true);
            extJsObject.setMsg("上傳成功!");
            extJsObject.setResult(this.fileName);
        } catch (Exception e) {
            extJsObject.setSuccess(false);
            extJsObject.setMsg("上傳失敗!");
            log.error("圖片上傳失敗", e);
        }
        return extJsObject;
    }
}

好了,就講到這兒了,至於頁面顯示的問題,大家可以作一些顯示、隱藏或者樣式的調整,希望給大家帶來幫助!