今天作商城上传商品的的时候遇到一个需求,就是上传图片的时候须要经过多个上传图片域,上传不一样的图片,之前由于项目进度很紧张,采起了一种应急措施:经过一个文件域上传,以下图: html
以前用的是dropzone来上传图片,今天研究了良久,发现dropzone很难实现这样一个需求,因而换了一个上传图片插件:webuploader。 前端
webuploader是一款由百度前端研发部开发的很是优秀的上传图片插件,采用大文件分片并发上传,支持经常使用图片格式jpg,jpeg,gif,bmp,png预览与压缩,节省网络数据传输,支持文件多选,类型过滤,拖拽(文件&文件夹),图片粘贴功能等功能。官网地址:http://fex.baidu.com/webuploader/ java
以后咱们能够经过官网的一些例子快速上手这个插件,当咱们经过官网的例子,能够作出相似以下的效果: web
(图片那些是我本身加的,先不要管),当咱们想要加入加入多个文件域的时候咱们因该怎么作呢? api
<div id="uploader"> <div id="queueListindex"> <span>首页图(最多1张图片)</span> <div id="dndArea" class="placeholder" style="margin-top: 20px"> <div id="filePicker"></div> <p>单次最多可选1张</p> </div> </div> <div id="queueListgalley"> <span>轮播图(最多3张图片)</span> <div id="dndArea1" class="placeholder" style="margin-top: 80px"> <div id="filePicker1"></div> <p>单次最多可选3张</p> </div> </div> <div id="queueListdescrip"> <span>详情图(最多4张图片)</span> <div id="dndArea2" class="placeholder" style="margin-top: 80px"> <div id="filePicker3"></div> <p>单次最多可选4张</p> </div> </div><div class="statusBar" style="display:none;"> <div class="progress"> <span class="text">0%</span> <span class="percentage"></span> </div> <div class="info"></div> <div class="btns"> <div id="filePicker2"></div> </div> </div> <div class="uploadBtn am-btn am-btn-primary"><input type="submit" class="am-btn am-btn-primary" value="开始上传"> </div>
</div>
在这里咱们初始化了3个选择图片的布局域(id为queueListindex,queueListgalley,queueListdescrip),而且初始化了上传商品的按钮,以后咱们须要在咱们的js文件里面初始化控件并激活选择图片按钮 浏览器
var $wrap = $('#uploader'), // 图片容器 $queueIndex = $('<ul class="filelist"></ul>') .appendTo($wrap.find('#queueListindex')), // 图片容器 $queueGalley = $('<ul class="filelist"></ul>') .appendTo($wrap.find('#queueListgalley')), // 图片容器 $queueDescrip = $('<ul class="filelist"></ul>') .appendTo($wrap.find('#queueListdescrip')), // 状态栏,包括进度和控制按钮 $statusBar = $wrap.find('.statusBar'), // 文件整体选择信息。 $info = $statusBar.find('.info'), // 上传按钮 $upload = $wrap.find('.uploadBtn'), // 没选择文件以前的内容。 $placeHolderIndex = $wrap.find('#dndArea'), $placeHolderGalley = $wrap.find('#dndArea1'), $placeHolderaDescrip = $wrap.find('#dndArea2'),
uploader = WebUploader.create({ pick: { //选择按钮 id: '#filePicker1', label: '点击选择图片', multiple: true }, formData: { //表单附带的能够写在这,若是只上传图片就能够不要 uid: uid }, threads:1, //同一时间只容许一个图片上传 dnd: '#dndArea', paste: '#uploader', swf: contextPath + '/resources/js/webUploader/Uploader.swf', //改为本身的Uploader.swf地址 chunked: false, chunkSize: 512 * 1024, duplicate:true, //是否容许重复的图片上传 server: contextPath + '/zhu/shelves', //接收表单的地址 runtimeOrder: 'flash', accept: { title: 'Images', extensions: 'gif,jpg,jpeg,bmp,png', mimeTypes: 'image/*' }, multiple: true, // 禁掉全局的拖拽功能。这样不会出现图片拖进页面的时候,把图片打开。 disableGlobalDnd: true, fileNumLimit: 15, fileSizeLimit: 20 * 1024 * 1024, // 200 M fileSingleSizeLimit: 10 * 1024 * 1024 // 50 M });
这里咱们初始化了咱们的控件,而后咱们继续添加咱们的剩下的上传按钮 服务器
uploader.addButton({ id: '#filePicker', innerHTML: '选择文件' }); uploader.addButton({ id: '#filePicker3', innerHTML: '选择文件' });
在这里咱们能够添加咱们的剩下的两个按钮,以后咱们的3个文件域就差很少出来了,以下图: 网络
在这个地方我遇到了一个问题,当我每次点击上传图片的时候,我须要肯定我当前选定的这个文件域是那个文件域,可是当我用jq的on事件绑定咱们选择文件按钮的控件的时候,我本身绑定的on会失效,找了下缘由,因该是当我点击选择文件的时候会弹出上传文件,两个事件重复绑定形成的,因此我换了种思路,利用 并发
var mybutton;//标志位 $('#filePicker1').on('mouseover', function () { mybutton = 1; }); $('#filePicker').on('mouseover', function () { mybutton = 0; }); $('#filePicker3').on('mouseover', function () { mybutton = 2; });
以后又有一个需求,咱们在不一样文件域的图片的最大数是不一样的,例如:咱们的queueListindex域里面就只容许有一张图片 app
翻了下webuploder api文档,有一个'beforeFileQueued'事件用于处理当咱们的文件加入上传队列以前的操做。
uploader.on('beforeFileQueued', function (file) { if (mybutton == 0) { fileCountIndex++; //首页域的文件数量 if (fileCountIndex > 1) { return false; } } else if (mybutton == 1) { fileCountGalley++;//轮播域的文件数量 if (fileCountGalley > 3) { return false; } } else if (mybutton == 2) { fileCountDescrip++;//详情域的文件数量 if (fileCountDescrip > 4) { return false; } } });
在这个事件里面,咱们经过当前的文件域来判断在当前这个文件域文件数达到最大值时则不能上传图片,若是不能,那么返回false,不让图片加入咱们的队列。
当咱们文件加入队列后,咱们须要把加入队列的文件显示到咱们的页面上,咱们能够经过onFileQueued事件,处理在队列里面的图片
uploader.onFileQueued = function (file) { if (mybutton == 0) { fileSizeIndex += file.size; if (fileCountIndex === 1) { $placeHolderIndex.addClass('element-invisible');//把咱们对应的上传域隐藏,以后咱们会添加控件显示咱们添加了的图片。 $statusBar.show(); } } else if (mybutton == 1) { fileSizeGalley += file.size; if (fileCountGalley === 1) { $placeHolderGalley.addClass('element-invisible'); $statusBar.show(); } } else if (mybutton == 2) { fileSizeDescrip += file.size; if (fileCountDescrip === 1) { $placeHolderaDescrip.addClass('element-invisible'); $statusBar.show(); } } addFile(file); //添加文件 setState('ready'); //设置状态,代码没贴出 updateTotalProgress();//更新进度,代码没贴出 };
function addFile(file) { var $li = $('<li id="' + file.id + '">' + '<p class="title">' + file.name + '</p>' + '<p class="imgWrap"></p>' + '<p class="progress"><span></span></p>' + '</li>'), //新建一个布局用于存放咱们的图片 $btns = $('<div class="file-panel">' + '<span class="cancel">删除</span>' + '<span class="rotateRight">向右旋转</span>' + '<span class="rotateLeft">向左旋转</span></div>').appendTo($li), $prgress = $li.find('p.progress span'), $wrap = $li.find('p.imgWrap'), $info = $('<p class="error"></p>'), showError = function (code) { switch (code) { case 'exceed_size': text = '文件大小超出'; break; case 'interrupt': text = '上传暂停'; break; default: text = '上传失败,请重试'; break; } $info.text(text).appendTo($li); }; var suffix = file.name.split('.')[file.name.split('.').length - 1]; //记录文件后缀名 if (mybutton == 0) { file.name = "index" + i + "." + suffix;//给文件命名,根据前缀来区分是哪一类的图片 $li.appendTo($queueIndex); } else if (mybutton == 1) { file.name = "galley" + i + "." + suffix; $li.appendTo($queueGalley); } else if (mybutton == 2) { file.name = "describe" + i + "." + suffix; $li.appendTo($queueDescrip); } i++; }
当咱们作到这一步的时候,其实已经能够上传图片到咱们的服务器了,可是当咱们须要连同表单一块儿上传进入服务器的话咱们就须要uploadBeforeSend事件来处理:
uploader.on('uploadBeforeSend', function (obj, data) { //data.bbb="sadasd"; //alert(uid); data.uid = uid; data.goods_name = $("input[name='goods_name']").val(); data.type = $("input[name='type']").val(); data.price = $("input[name='price']").val(); data.goods_number = $("input[name='goods_number']").val(); mydiv = $('#my_select'); data.categoryId = $(mydiv.children('select')[mydiv.children('select').length - 1]).children('option:selected').val(); data.descri = $("input[name='descri']").val(); });
像这种格式,直接把data后面跟上参数名就能够给参数赋值。
$upload.on('click', function () { uploader.upload(); });
再经过 uploader.upload() 来上传咱们的表单,以后的话图片和表单就能够上传进咱们的服务器了,以下图:
在这里尚未完,由于咱们的webuploder是采起分片上传图片的,每次只上传一张图片,不像dropzone同样,一次上传全部的图片,因而乎就涉及到一个问题,之前的服务器端的代码不能用了,因此我把服务器端的代码改了一下,适应咱们的前端的需求。
在前端的话咱们须要每次上传的时候添加个标识位:
var uid = 0;
以后咱们把uid上传进服务器端
String myId = request.getParameter("uid"); if (myId.equals("0")){ //建立新的商品,并保存图片 }else{ //把图片保存进刚刚新建的商品里面 }
当咱们服务器端收到第一张图片时会自动的生成一条商品信息,以后咱们会返回咱们刚刚生成的商品的id给咱们的浏览器,上传成功,浏览器接收后
uploader.on('uploadSuccess', function (file, response) { uid = response.text; });
咱们把返回的商品Id赋值给咱们的标志位uid, 而后由于咱们的webuploder是分片上传的,刚开始初始化时咱们须要把threads设置为1,
threads: 1,
由于这样咱们图片会等一张传完了后才开始上传第二张,因此咱们就把咱们返回的商品id上传给了咱们的服务器,以后在服务器端判断后把图片存入对应的商品