- A+
所属分类:Web前端
最近有个项目要在浏览器端裁剪并上传图片。由于缺乏人力,只能我上阵杀敌。通过参考各种文章,最后决定用cropperjs进行图片裁剪,用webuploader上传文件。本文涉及到的知识至少有Java基础、SpringMVC、thymeleaf模版引擎、JS基础、JQuery基础、Bootstrap组件,但是文章重点只是cropperjs和webuploader的组合运用,其他的都是辅助。
1. 依赖JS库
webuploader官网
cropperjs演示主页
cropperjs开源主页
2. 核心流程
- 2.1 选择文件按钮
previewImg用于预览上传后的图片;picker用于选择图片,webuploader会自动给picker赋予选择文件的特性。fileInput用于接收文件数据。
<div class="form-group"> <img id="previewImg" width="200px" /> <div> <a href="javascript:void(0)" id="picker">选择图片</a> <input type="file" id="fileInput" style="display: none" /> </div> </div>
下面代码给fileInput组件触发了点击事件
$("#picker").on('click', function () { $("#fileInput").trigger("click"); });
- 2.2 定义组件参数和事件
以下代码定义上传组件对象
var uploader = WebUploader.create({ auto: true,// 选完文件后,是否自动上传。 server: '/upload', fileSingleSizeLimit: 2 * 1024 * 1024, duplicate: true, accept: {// 只允许选择图片文件。 title: 'Images', extensions: 'jpg,jpeg,png', mimeTypes: 'image/jpg,image/jpeg,image/png' }, //如果有表单数据要上传,可以给formData赋值 formData: { id: 0 } });
以下代码定义上传组件事件。WebUploader组件不提供UI,如果需要定制界面,实现下面的方法即可。
//提交额外的表单数据 uploader.on('uploadBeforeSend', function (object, data, header) { data.id = $('#id').val(); }); // 当有文件被添加进队列的时候 uploader.on('fileQueued', function (file) { $('#file_list').append('<div id="' + file.id + '" class="item">' + '<h4 class="info">' + file.name + '</h4>' + '<p class="state">等待上传...</p>' + '</div>'); }); // 上传成功 uploader.on('uploadSuccess', function (file, response) { $('#' + file.id).find('p.state').text('已上传'); console.log(response._raw); var object = $.parseJSON(response._raw); //给预览组件赋值 $('#previewImg').attr("src", object.url); }); // 上传发生错误 uploader.on('uploadError', function (file) { $('#' + file.id).find('p.state').text('上传出错'); }); // 上传中 uploader.on('startUpload', function (file, rs) { console.log("文件正在上传中,请稍候"); });
- 2.3 定义裁剪组件参数和事件
以下代码定义裁剪图片的对话框,cropperImage是上传后的图片,被裁剪的目标对象。
<div class="modal" id="cropperImageModal" tabindex="-1" role="dialog" aria-labelledby="cropperImageModal" aria-hidden="true"> <div class="modal-dialog" style="width: 50%;"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <h4 class="modal-title">裁剪图片</h4> </div> <div class="modal-body"> <!-- cropperImage是上传后的图片,被裁剪的目标对象 --> <img src="" id="cropperImage" style="max-width: 100%"/> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal" id="modalClose">关闭</button> <button type="button" class="btn btn-primary" id="modalSubmit">保存</button> </div> </div> </div> </div>
以下代码定义图片裁剪参数,更多参数参考cropper.js的API详解。如果不需要固定裁剪区域大小,删除ready函数即可。
var cropperImage = $("#cropperImage"); var cropperOptions = { viewMode: 1, dragMode: 'none', aspectRatio: 1, background: false, autoCropArea: 0.6, crop: function (event) { //裁剪的实时事件 console.log(event.detail.width); console.log(event.detail.height); }, ready: function () { //限定裁剪区域大小为500 cropperImage.cropper('crop'); cropperImage.cropper('setData', { width: 500, height: 500 }) } };
- 2.5 触发裁剪和上传事件
fileInput组件的change事件会采用FileReader对象获得上传的Image,初始化cropperjs裁剪方法。
$("#fileInput").on('change', function () { var file = this.files[0]; //定义读文件对象 var reader = new FileReader(); reader.onload = function () { imageOnload(reader.result); }; reader.readAsDataURL(file);//File对象转换为dataURL }); //图片对象加载方法 function imageOnload(url) { var cropperImg = new Image(); cropperImg.src = url; //destroy方法是为了重入不出错 cropperImage.cropper('destroy').attr('src', url).cropper(cropperOptions); cropperImg.onload = function () { //弹窗裁剪 $('#cropperImageModal').modal(); $("#modalClose").on('click', function () { $("#fileInput").val(''); $('#cropperImageModal').modal('hide'); }); $("#modalSubmit").on('click', function () { var canVas = $("#cropperImage").cropper("getCroppedCanvas", {});//获取裁剪后得到的canvas数据 var file = convertBase64UrlToBlob(canVas.toDataURL('image/jpeg', '0.0'));//将canvas转换为Blob格式 uploader.addFiles(file);//将裁剪后的图片添加进webuploader上传到后台 $('#cropperImageModal').modal('hide'); $("#fileInput").val(''); }); }; }
采用cropperImage.cropper('getCroppedCanvas').toblob(function(blob){})
也可以获取图片二进制对象,但是默认是png格式,体积很大,不利于网络传输,采用下面的方法可以指定图片格式。
/** * base64转为blob,图片为jpeg格式 */ function convertBase64UrlToBlob(urlData) { //去掉url的头,并转换为byte var bytes = window.atob(urlData.split(',')[1]); //处理异常,将ascii码小于0的转换为大于0 var ab = new ArrayBuffer(bytes.length); var ia = new Uint8Array(ab); for (var i = 0; i < bytes.length; i++) { ia[i] = bytes.charCodeAt(i); } return new Blob([ab], {type: 'image/jpeg'}); }
- 2.6 后端接口实现
@Controller public class IndexController { protected final Logger logger = LoggerFactory.getLogger(getClass()); @RequestMapping("/index") public String list(ModelMap map) { return "index"; } @PostMapping("/upload") @ResponseBody public UploadFileVo uploadFile(@RequestParam("file") MultipartFile file, @RequestParam("id") Integer id, HttpServletResponse response) { response.setContentType("text/html"); //保存图片到服务端,返回访问地址 UploadFileVo uploadFileVo = new UploadFileVo(); //这里为了演示,返回一张网图 uploadFileVo.setUrl("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png"); logger.info("上传成功,url:{},id:{}", uploadFileVo.getUrl(), id); return uploadFileVo; } }
- 2.7 最终效果图