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