好久没有写博客了,感觉都不习惯了。一方面是因为工作占用的时间过多,另一方面是自己有点懒,没有坚持。好了,少扯这些没用的东西,直入主题呗。
笔者目前在公司会接触到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:https://github.com/fengyuanchen/cropper/
- webuploader:http://fex.baidu.com/webuploader/
一、插件目录结构介绍
笔者这个例子的目录结构以及所需插件,截图如下:
二、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;
}
}
好了,就讲到这儿了,至于页面显示的问题,大家可以作一些显示、隐藏或者样式的调整,希望给大家带来帮助!