WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件。
具体接口参考 webuploader接口文档地址
一、图片上传功能
引入资源
<!--引入CSS--> <link rel="stylesheet" type="text/css" href="webuploader/webuploader.css"><!--引入JS--> <script type="text/javascript" src="webuploader/webuploader.js"></script>
html
<div id="uploader" class="wu-example"><div class="queueList"><div id="dndArea" class="placeholder"><div id="filePicker"></div><p>或将照片拖到这里,单次最多可选300张</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 class="uploadBtn">开始上传</div></div></div></div>
css样式
#container {color: #838383;font-size: 12px;
}#uploader .queueList {margin: 20px;border: 3px dashed #e6e6e6;
}
#uploader .queueList.filled {padding: 17px;margin: 0;border: 3px dashed transparent;
}
#uploader .queueList.webuploader-dnd-over {border: 3px dashed #999999;
}#uploader p {margin: 0;}.element-invisible {position: absolute !important;clip: rect(1px 1px 1px 1px); /* IE6, IE7 */clip: rect(1px,1px,1px,1px);
}#uploader .placeholder {min-height: 350px;padding-top: 178px;text-align: center;background: url(../../../img/webuploader.png) center 93px no-repeat;color: #cccccc;font-size: 18px;position: relative;
}#uploader .placeholder .webuploader-pick {font-size: 18px;background: #00b7ee;border-radius: 3px;line-height: 44px;padding: 0 30px;*width: 120px;color: #fff;display: inline-block;margin: 0 auto 20px auto;cursor: pointer;box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
}#uploader .placeholder .webuploader-pick-hover {background: #00a2d4;
}#uploader .placeholder .flashTip {color: #666666;font-size: 12px;position: absolute;width: 100%;text-align: center;bottom: 20px;
}
#uploader .placeholder .flashTip a {color: #0785d1;text-decoration: none;
}
#uploader .placeholder .flashTip a:hover {text-decoration: underline;
}#uploader .filelist {list-style: none;margin: 0;padding: 0;
}#uploader .filelist:after {content: '';display: block;width: 0;height: 0;overflow: hidden;clear: both;
}#uploader .filelist li {width: 110px;height: 110px;background: url(../../img/bg.png) no-repeat;text-align: center;margin: 0 8px 20px 0;position: relative;display: inline;float: left;overflow: hidden;font-size: 12px;
}#uploader .filelist li p.log {position: relative;top: -45px;
}#uploader .filelist li p.title {position: absolute;top: 0;left: 0;width: 100%;overflow: hidden;white-space: nowrap;text-overflow : ellipsis;top: 5px;text-indent: 5px;text-align: left;
}#uploader .filelist li p.progress {position: absolute;width: 100%;bottom: 0;left: 0;height: 8px;overflow: hidden;z-index: 50;margin: 0;border-radius: 0;background: none;-webkit-box-shadow: 0 0 0;
}
#uploader .filelist li p.progress span {display: none;overflow: hidden;width: 0;height: 100%;background: #1483d8 url(../../img/progress.png) repeat-x;-webit-transition: width 200ms linear;-moz-transition: width 200ms linear;-o-transition: width 200ms linear;-ms-transition: width 200ms linear;transition: width 200ms linear;-webkit-animation: progressmove 2s linear infinite;-moz-animation: progressmove 2s linear infinite;-o-animation: progressmove 2s linear infinite;-ms-animation: progressmove 2s linear infinite;animation: progressmove 2s linear infinite;-webkit-transform: translateZ(0);
}@-webkit-keyframes progressmove {0% {background-position: 0 0;}100% {background-position: 17px 0;}
}
@-moz-keyframes progressmove {0% {background-position: 0 0;}100% {background-position: 17px 0;}
}
@keyframes progressmove {0% {background-position: 0 0;}100% {background-position: 17px 0;}
}#uploader .filelist li p.imgWrap {position: relative;z-index: 2;line-height: 110px;vertical-align: middle;overflow: hidden;width: 110px;height: 110px;-webkit-transform-origin: 50% 50%;-moz-transform-origin: 50% 50%;-o-transform-origin: 50% 50%;-ms-transform-origin: 50% 50%;transform-origin: 50% 50%;-webit-transition: 200ms ease-out;-moz-transition: 200ms ease-out;-o-transition: 200ms ease-out;-ms-transition: 200ms ease-out;transition: 200ms ease-out;
}#uploader .filelist li img {width: 100%;
}#uploader .filelist li p.error {background: #f43838;color: #fff;position: absolute;bottom: 0;left: 0;height: 28px;line-height: 28px;width: 100%;z-index: 100;
}#uploader .filelist li .success {display: block;position: absolute;left: 0;bottom: 0;height: 40px;width: 100%;z-index: 200;background: url(../../img/success.png) no-repeat right bottom;
}#uploader .filelist div.file-panel {position: absolute;height: 0;filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#80000000', endColorstr='#80000000')\0;background: rgba( 0, 0, 0, 0.5 );width: 100%;top: 0;left: 0;overflow: hidden;z-index: 300;
}#uploader .filelist div.file-panel span {width: 24px;height: 24px;display: inline;float: right;text-indent: -9999px;overflow: hidden;background: url(../../img/icons.png) no-repeat;margin: 5px 1px 1px;cursor: pointer;
}#uploader .filelist div.file-panel span.rotateLeft {background-position: 0 -24px;
}
#uploader .filelist div.file-panel span.rotateLeft:hover {background-position: 0 0;
}#uploader .filelist div.file-panel span.rotateRight {background-position: -24px -24px;
}
#uploader .filelist div.file-panel span.rotateRight:hover {background-position: -24px 0;
}#uploader .filelist div.file-panel span.cancel {background-position: -48px -24px;
}
#uploader .filelist div.file-panel span.cancel:hover {background-position: -48px 0;
}#uploader .statusBar {height: 63px;border-top: 1px solid #dadada;padding: 0 20px;line-height: 63px;vertical-align: middle;position: relative;
}#uploader .statusBar .progress {border: 1px solid #1483d8;width: 198px;background: #fff;height: 18px;position: relative;display: inline-block;text-align: center;line-height: 20px;color: #6dbfff;position: relative;margin: 0 10px 0 0;
}
#uploader .statusBar .progress span.percentage {width: 0;height: 100%;left: 0;top: 0;background: #1483d8;position: absolute;
}
#uploader .statusBar .progress span.text {position: relative;z-index: 10;
}#uploader .statusBar .info {display: inline-block;font-size: 14px;color: #666666;
}#uploader .statusBar .btns {position: absolute;top: 10px;right: 20px;line-height: 40px;
}#filePicker2 {display: inline-block;float: left;
}#uploader .statusBar .btns .webuploader-pick,
#uploader .statusBar .btns .uploadBtn,
#uploader .statusBar .btns .uploadBtn.state-uploading,
#uploader .statusBar .btns .uploadBtn.state-paused {background: #ffffff;border: 1px solid #cfcfcf;color: #565656;padding: 0 18px;display: inline-block;border-radius: 3px;margin-left: 10px;cursor: pointer;font-size: 14px;float: left;
}
#uploader .statusBar .btns .webuploader-pick-hover,
#uploader .statusBar .btns .uploadBtn:hover,
#uploader .statusBar .btns .uploadBtn.state-uploading:hover,
#uploader .statusBar .btns .uploadBtn.state-paused:hover {background: #f0f0f0;
}#uploader .statusBar .btns .uploadBtn {background: #00b7ee;color: #fff;border-color: transparent;
}
#uploader .statusBar .btns .uploadBtn:hover {background: #00a2d4;
}#uploader .statusBar .btns .uploadBtn.disabled {pointer-events: none;opacity: 0.6;
}
用于保存swf文件 的html 文件
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>403 Forbidden</title> </head><body> <h1>Forbidden</h1> <p>You don't have permission to access /theme/hplus/js/plugins/webuploader/ on this server.</p> <hr> <address>Apache Server at www.zi-han.net Port 80</address> </body></html>
上js代码
var BASE_URL = 'js/plugins/webuploader/index.html'; //保存swf文件 jQuery(function() {function e(e) {var a = o('<li id="' + e.id + '"><p class="title">' + e.name + '</p><p class="imgWrap"></p><p class="progress"><span></span></p></li>'),s = o('<div class="file-panel"><span class="cancel">删除</span><span class="rotateRight">向右旋转</span><span class="rotateLeft">向左旋转</span></div>').appendTo(a),i = a.find("p.progress span"),t = a.find("p.imgWrap"),r = o('<p class="error"></p>'),d = function(e) {switch (e) {case "exceed_size":text = "文件大小超出";break;case "interrupt":text = "上传暂停";break;default:text = "上传失败,请重试"}r.text(text).appendTo(a)};"invalid" === e.getStatus() ? d(e.statusText) : (t.text("预览中"), n.makeThumb(e,function(e, a) {if (e) return void t.text("不能预览");var s = o('<img src="' + a + '">');t.empty().append(s)},v, b), w[e.id] = [e.size, 0], e.rotation = 0),e.on("statuschange",function(t, n) {"progress" === n ? i.hide().width(0) : "queued" === n && (a.off("mouseenter mouseleave"), s.remove()),"error" === t || "invalid" === t ? (console.log(e.statusText), d(e.statusText), w[e.id][1] = 1) : "interrupt" === t ? d("interrupt") : "queued" === t ? w[e.id][1] = 0 : "progress" === t ? (r.remove(), i.css("display", "block")) : "complete" === t && a.append('<span class="success"></span>'),a.removeClass("state-" + n).addClass("state-" + t)}),a.on("mouseenter",function() {s.stop().animate({height: 30})}),a.on("mouseleave",function() {s.stop().animate({height: 0})}),s.on("click", "span",function() {var a, s = o(this).index();switch (s) {case 0:return void n.removeFile(e);case 1:e.rotation += 90;break;case 2:e.rotation -= 90}x ? (a = "rotate(" + e.rotation + "deg)", t.css({"-webkit-transform": a,"-mos-transform": a,"-o-transform": a,transform: a})) : t.css("filter", "progid:DXImageTransform.Microsoft.BasicImage(rotation=" + ~~ (e.rotation / 90 % 4 + 4) % 4 + ")")}),a.appendTo(l)}function a(e) {var a = o("#" + e.id);delete w[e.id],s(),a.off().find(".file-panel").off().end().remove()}function s() {var e, a = 0,s = 0,t = f.children();o.each(w,function(e, i) {s += i[0],a += i[0] * i[1]}),e = s ? a / s: 0,t.eq(0).text(Math.round(100 * e) + "%"),t.eq(1).css("width", Math.round(100 * e) + "%"),i()}function i() {var e, a = "";"ready" === k ? a = "选中" + m + "张图片,共" + WebUploader.formatSize(h) + "。": "confirm" === k ? (e = n.getStats(), e.uploadFailNum && (a = "已成功上传" + e.successNum + "张照片至XX相册," + e.uploadFailNum + '张照片上传失败,<a class="retry" href="#">重新上传</a>失败图片或<a class="ignore" href="#">忽略</a>')) : (e = n.getStats(), a = "共" + m + "张(" + WebUploader.formatSize(h) + "),已上传" + e.successNum + "张", e.uploadFailNum && (a += ",失败" + e.uploadFailNum + "张")),p.html(a)}function t(e) {var a;if (e !== k) {switch (c.removeClass("state-" + k), c.addClass("state-" + e), k = e) {case "pedding":u.removeClass("element-invisible"),l.parent().removeClass("filled"),l.hide(),d.addClass("element-invisible"),n.refresh();break;case "ready":u.addClass("element-invisible"),o("#filePicker2").removeClass("element-invisible"),l.parent().addClass("filled"),l.show(),d.removeClass("element-invisible"),n.refresh();break;case "uploading":o("#filePicker2").addClass("element-invisible"),f.show(),c.text("暂停上传");break;case "paused":f.show(),c.text("继续上传");break;case "confirm":if (f.hide(), c.text("开始上传").addClass("disabled"), a = n.getStats(), a.successNum && !a.uploadFailNum) return void t("finish");break;case "finish":a = n.getStats(),a.successNum ? alert("上传成功") : (k = "done", location.reload())}i()}}var n, o = jQuery,r = o("#uploader"),l = o('<ul class="filelist"></ul>').appendTo(r.find(".queueList")),d = r.find(".statusBar"),p = d.find(".info"),c = r.find(".uploadBtn"),u = r.find(".placeholder"),f = d.find(".progress").hide(),m = 0,h = 0,g = window.devicePixelRatio || 1,v = 110 * g,b = 110 * g,k = "pedding",w = {},x = function() {var e = document.createElement("p").style,a = "transition" in e || "WebkitTransition" in e || "MozTransition" in e || "msTransition" in e || "OTransition" in e;return e = null,a} ();if (!WebUploader.Uploader.support()) throw alert("不支持您的浏览器!如果你使用的是IE浏览器,请尝试升级 flash 播放器"),new Error("不支持您的浏览器");n = WebUploader.create({pick: {id: "#filePicker",label: "点击选择图片"},dnd: "#uploader .queueList",paste: document.body,accept: {title: "Images",extensions: "gif,jpg,jpeg,bmp,png",mimeTypes: "image/*"},swf: BASE_URL + "/Uploader.swf",disableGlobalDnd: !0,chunked: !0,server: "webuploader_photo.html",duplicate: true,fileNumLimit: 9,fileSizeLimit: 5242880,fileSingleSizeLimit: 1048576,headers: {"X-CSRFToken": $.cookie('csrftoken')},}),n.addButton({id: "#filePicker2",label: "继续添加"}),n.onUploadProgress = function(e, a) {var i = o("#" + e.id),t = i.find(".progress span");t.css("width", 100 * a + "%"),w[e.id][1] = a,s()},n.on('uploadSuccess', function (file, response) {var res=JSON.parse(response._raw); //这里可以得到后台返回的数据// $('#' + file.id).addClass('upload-state-done');var input = document.createElement("input");console.log(res.data)var data = res.datainput.type="hidden";input.name=data.id;input.value=data.path;$("#"+data.id).append(input);console.log($("#"+data.id)) });n.onFileQueued = function(a) {m++,h += a.size,1 === m && (u.addClass("element-invisible"), d.show()),e(a),t("ready"),s()},n.onFileDequeued = function(e) {m--,h -= e.size,m || t("pedding"),a(e),s()},n.on("all",function(e) {switch (e) {case "uploadFinished":t("confirm");break;case "startUpload":t("uploading");break;case "stopUpload":t("paused")}}),n.onError=function(e){// alert("Error: "+e)switch (e) {case 'Q_EXCEED_NUM_LIMIT':alert("错误:最多上传九张图片!");break;case 'Q_EXCEED_SIZE_LIMIT':alert.msg("错误:文件总大小超出限制!");break;case 'F_EXCEED_SIZE':alert.msg("错误:文件大小超出限制!");break;case 'Q_TYPE_DENIED':alert.msg("错误:禁止上传该类型文件!");break;case 'F_DUPLICATE':alert.msg("错误:请勿重复上传该文件!");break;default:alert.msg('错误代码:' + type);break;}},c.on("click",function() {return o(this).hasClass("disabled") ? !1 : void("ready" === k ? n.upload() : "paused" === k ? n.upload() : "uploading" === k && n.stop())}),p.on("click", ".retry",function() {n.retry()}),p.on("click", ".ignore",function() {alert.msg("已忽略")}),c.addClass("state-" + k),s()});
服务端接收上传文件
def webuploader_photo(request):ret = {"status": False, "data": {"path": "", "name": ""}, "summary": ""}target_path = "media/upload/goods/"try:# 获取文件对象post_obj = request.POSTfile_obj = request.FILES.get("file")raw_name = file_obj.nameraw_id = post_obj.get("id")postfix = raw_name.split(".")[-1]if file_obj:file_name = str(uuid.uuid4()) + "." + postfixif not os.path.exists(os.path.dirname(target_path)):os.makedirs(target_path)file_path = os.path.join(target_path, file_name)# os.path.join()在Linux/macOS下会以斜杠(/)分隔路径,而在Windows下则会以反斜杠(\)分隔路径,# 故统一路径将'\'替换成'/'file_path = file_path.replace('\\', "/")with open(file_path, "wb") as f:for chunk in file_obj.chunks():f.write(chunk)ret["status"] = Trueret["data"]['path'] = file_pathret["data"]['name'] = raw_nameret["data"]["id"] = raw_idexcept Exception as e:ret["summary"] = str(e)return HttpResponse(json.dumps(ret))
python接收webuploader上传文件
webuploader真的是一个非常强大的文件上传组件
二 、服务端数据回显和编辑功能实现
html
<div class="page-container"><div id="uploader" class="uploader" ><div class="wrapper" class="placeholder"><div class="file-list"></div><p>或将照片拖到这里,单次最多可选9张</p></div><div class="actions-area"><div class="actions"><div class="filePicker action">选择图片</div><div class="uploadFile action upload-btn disabled">上传图片</div></div></div></div></div><script type="text/javascript">var BASE_URL = '/static/plugins/webuploader/index.html';//webuploader 相关配置 var uploader = new WebUploaderSupport({server: "webuploader_photo.html",paste: document.body,swf: BASE_URL + "/Uploader.swf", // swf文件所处路径 support: {uploader: "#uploader", //上传区域容器选择器 fileSize: 9, //文件总个数, -1时无限制 serverFiles: HandlerFile(),{#[{"src":"","name":"2.PNG","attrs":{"data-server-file":true,"data-delete-url":""}}]#}},duplicate: true,fileNumLimit: 9,fileSizeLimit: 5242880,fileSingleSizeLimit: 1048576,headers: {"X-CSRFToken": $.cookie('csrftoken')},}); </script>
css
.uploader {position: relative;padding: 15px 15px;margin: 15px 0;background-color: #fafafa;box-shadow: inset 0 3px 6px rgba(0, 0, 0, .05);border-color: #e5e5e5 #eee #eee;border-style: solid;border-width: 1px 0;min-width: 250px;
}.uploader:after {display: block;content: "";overflow: hidden;clear: both;
}.uploader .message {font-size: 16px;margin-bottom: 20px;
}.uploader .wrapper {text-align: center;border: 3px dashed #ccc;/* background: url(../images/image.png) center 93px no-repeat;*/color: #cccccc;font-size: 18px;position: relative;
}.file-list {list-style: none;margin: 0;padding: 0;
}.file-list:after {display: block;content: "";overflow: hidden;clear: both;
}.file-list .file-item {float: left;width: 150px;height: 150px;margin: 5px;border: 1px solid;overflow: hidden;position: relative;
}.file-list .file-item img {width: 100%;height: 100%;
}.file-list .file-item .file-delete, .file-list .file-item .file-retry {display: none;position: absolute;width: 100px;height: 30px;left: 50%;margin-left: -50px;margin-top: -15px;top: 50%;z-index: 1;
}/*重试时显示重试按钮*/
.file-list .file-item.retry:hover .file-retry {display: block;
}/*删除重试按钮样式*/
.file-list .file-item button {outline: none !important;border: 0;padding: 5px 12px;opacity: 0.9;color: #fff!important;text-align: center;border-radius: 3px;display: inline-block;margin-bottom: 0;font-size: 14px;font-weight: 400;line-height: 1.42857143;white-space: nowrap;vertical-align: middle;-ms-touch-action: manipulation;touch-action: manipulation;cursor: pointer;-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;
}/*删除按钮*/
.file-list .file-item .file-delete button {background: #f14641;
}.file-list .file-item .file-delete button:hover {background: #f1281a;
}.file-list .file-item .file-retry button {background: #daa7ff;
}.file-list .file-item .file-retry button:hover {background: #bf8cff;
}/*重试时进度条隐藏*/
.file-list .file-item.retry .progress {display: none!important;
}.file-list .file-item:hover .file-delete {display: block;
}/*不能预览时的提示*/
.file-list .file-item .preview-tips {position: absolute;width: 100px;height: 20px;font-size: 16px;left: 50%;margin-left: -50px;color: #949390;margin-top: -10px;top: 50%;overflow: hidden;z-index: 1;
}/*鼠标经过当前item时隐藏提示不能预览的内容*/
.file-list .file-item:hover .preview-tips {z-index: -1;
}
/*鼠标经过当前item时如果是不能编辑则不隐藏文字*/
.file-list .file-item.not-edit:hover .preview .preview-tips {z-index: 1;
}
.file-list .file-item.not-edit:hover .file-delete {display: none;
}.file-list .file-item.not-edit:hover .file-retry {display: none;
}.file-item .file-info {position: absolute;left: 4px;bottom: 4px;right: 4px;height: 20px;line-height: 20px;text-indent: 5px;background: rgba(0, 0, 0, 0.6);color: white;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;font-size: 12px;z-index: 1;
}.file-item .state {position: absolute;left: 4px;top: 4px;right: 4px;height: 20px;line-height: 20px;text-indent: 5px;background: rgba(0, 0, 0, 0.6);color: white;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;font-size: 12px;z-index: 1;
}.file-item .state.ready {background: rgba(169, 64, 64, 0.6);
}.file-item .state.success {background: rgba(68, 247, 22, 0.6);
}.file-item .state.error {background: red;
}/*进度条*/
.file-item .progress {display: none;position: absolute;width: 120px;height: 14px;left: 50%;margin-left: -60px;margin-top: -7px;top: 50%;
}.actions-area {height: 55px;position: relative;
}.actions {position: absolute;top: 15px;right: 0px;
}.actions .action {display: inline-block;float: left;height: 40px;
}.upload-btn {outline: none !important;cursor: pointer;border: 0;padding: 10px 15px;background: #76d67d!important;color: #fff!important;text-align: center;border-radius: 3px;overflow: hidden;margin-left: 14px;
}.upload-btn:hover {background: #4bb953 !important;
}.upload-btn.disabled {background: #848080!important;
}.upload-btn.disabled:hover {background: #404040!important;
}/*上传时使某些内容不显示*/
.uploading {z-index: -1!important;
}.file-list .file-item.retry .file-delete {display: block;margin-top: 0;
}.file-list .file-item.retry button {padding: 2px 5px;
}.file-list .file-item.retry .file-retry {display: block;margin-top: -30px;
}.actions-area {font-size: 14px;font-weight: 400;line-height: 1.42857143;
}.actions-area button.disabled{cursor: not-allowed;filter: alpha(opacity=65);-webkit-box-shadow: none;box-shadow: none;opacity: .65;
}.actions-area button {margin-bottom: 0;font-size: 14px;font-weight: 400;line-height: 1.42857143;text-align: center;white-space: nowrap;vertical-align: middle;-ms-touch-action: manipulation;touch-action: manipulation;
}/*上传失败需要重试时未生成缩略图的提示文字隐藏*/
.file-list .file-item.retry .preview-tips {display: none;
}.progress {height: 20px;margin-bottom: 20px;overflow: hidden;background-color: #f5f5f5;border-radius: 4px;-webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.1);box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
}.progress-bar {float: left;width: 0;height: 100%;font-size: 12px;line-height: 20px;color: #fff;text-align: center;background-color: #337ab7;-webkit-box-shadow: inset 0 -1px 0 rgba(0,0,0,.15);box-shadow: inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition: width .6s ease;-o-transition: width .6s ease;transition: width .6s ease;
}
js
function WebUploaderSupport(options) {var that = this;var fileStatus = {inited: "inited", //初始状态queued: "queued", //已经进入队列, 等待上传progress: "progress", //上传中complete: "complete", //上传完成error: "error", //上传出错,可重试interrupt: "interrupt", //上传中断,可续传invalid: "invalid", //文件不合格,不能重试上传。会自动从队列中移除cancelled: "cancelled" //文件被移除};WebUploaderSupport.fileStatus = fileStatus;var $fns = {log: function (content) {if(support.log && console) {console.log(content);}},logInfo: function () {var support = that.support;if(!support) {this.log("WebUploader does not support the browser you are using.");} else {if(this.getUploader() == null) {this.log("WebUploader has not inited, please use it after inited.");}}},getUploader: function () {var uploader = that.uploader;return uploader;},getFiles: function () {var result = null;var uploader = this.getUploader();if(uploader) {result = uploader.getFiles();}return result;},getFileSize: function (status) {var result = 0;var uploader = this.getUploader();if(uploader) {if(status != null) {result = uploader.getFiles(status).length;} else {result = uploader.getFiles().length;}}return result;},getInitedFileSize: function () { //获取inited状态的文件个数return this.getFileSize('inited');},retry: function (file) {var uploader = this.getUploader();if(uploader) {if(that.edit) {if(file != null) {uploader.retry(file);} else {uploader.retry();}} else {this.log("can't retry, because not in edit mode");}}this.logInfo();},upload: function () {var uploader = this.getUploader();if(uploader) {if(that.edit) {uploader.upload();} else {this.log("can't upload, because not in edit mode");}}this.logInfo();},removeFileWithItem: function (file) {var uploader = that.uploader;if(file) {support.removeFileItem(support.getItem(file));if(uploader) {uploader.removeFile(file.id, true);}}}};that.$fns = $fns;options = options || {};var support = {$fns: {}, //公共函数$elements: {}, //区域jquery元素edit: true,uploader: ".uploader", //上传区域容器选择器dndWrapper: ".wrapper", //拖拽区域选择器chooseFileBtn: ".filePicker", //选择文件的按钮选择器uploadFileBtn: ".uploadFile", //上传文件的按钮选择器fileList: ".file-list", //显示文件列表的区域选择器fileListHeight: 150, //初始默认高度log: false, //是否打印信息multiple: true, //默认多选thumbnailWidth: 150,thumbnailHeight: 150,fileSize: -1, //文件总个数, -1时无限制instance: null, //uploader实例ratio: (function () {return window.devicePixelRatio || 1; //优化retina, 在retina下这个值是2})(),getActualThumbnailWidth: function () {var that = this;var ratio = that.ratio;return that.thumbnailWidth * ratio;},getActualThumbnailHeight: function () {var that = this;var ratio = that.ratio;return that.thumbnailHeight * ratio;},/*** 获取不能预览的文件的样式,可覆盖(可根据名称解析后返回img对象显示)* @param name 文件名* @param thumbnailHeight* @param thumbnailWidth* @returns {jQuery}*/getThumbErrorPreview: function (name, thumbnailHeight, thumbnailWidth) {var $element = $('<div class="preview"></div>').css({height: thumbnailHeight,width: thumbnailWidth}).append($('<div class="preview-tips">不能预览</div>'));return $element;//显示图片的方式//return $('<img src="../images/preview/1.jpg">');},showPreview: function ($item, file) { //显示文件中的预览效果var $preview = $('<img />');$item.append($preview);var uploader = this.instance;// 缩略图大小var thumbnailWidth = this.getActualThumbnailWidth(), thumbnailHeight = this.getActualThumbnailHeight();this.setItemStyle($item); //设置item宽高var self = this;uploader.makeThumb(file, function (error, src) {if (error) {$preview.replaceWith(self.getThumbErrorPreview(file.name, self.thumbnailHeight, self.thumbnailWidth));return;}$preview.attr('src', src);}, thumbnailWidth, thumbnailHeight);},getItem: function (file) { //获取$itemreturn $("#" + file.id);},setItemStyle: function ($item) { //设置缩略图所在容器的宽高,默认是均150px,用于加载文件预览时设置if($item) {var that = this;var thumbnailWidth = that.thumbnailWidth, thumbnailHeight = that.thumbnailHeight;$item.css({width: thumbnailWidth, height: thumbnailHeight}); //设置$item宽高}},loadUploadFileBtnStyle: function () { //用于加载上传按钮的样式var $fns = this.$fns;var $uploadFileBtn = this.$elements.$uploadFileBtn;if($fns && $uploadFileBtn) {var initedSize = $fns.getInitedFileSize();if (initedSize === 0) { //inited 文件个数$uploadFileBtn.addClass("disabled"); //上传按钮禁用} else {$uploadFileBtn.removeClass("disabled"); //移除上传按钮的禁用样式}}},retryFile: function ($item, file) {var $fns = this.$fns;$fns.retry(file);},renderItem: function (isFile, data) {var name = data.name || "";var html ='<div class="file-item thumbnail">' +'<div class="file-info">' + name + '</div>' +'<div class="file-operations">' +'<div class="file-delete">' + '<button type="button">' + '删除</button></div>' +'<div class="file-retry">' + '<button type="button">' + '重试</button></div>' +'</div>' +'<div class="progress">' +'<div class="progress-bar"></div>' +'</div>' +'</div>';var $item = $(html);if (!isFile) {//服务端显示数据时var $preview; //根据文件后缀进行展示预览结果if(/(.jpg|.png|.gif|.bmp|.jpeg)$/.test(name.toLocaleLowerCase())) {$preview = $('<img src="'+ data.src + '"/>');//自定义添加var $input =$('<input type="text" value="'+ data.src +'" class="hidden" >') ;$item.append($input);} else {$preview = this.getThumbErrorPreview(data.name, this.thumbnailHeight, this.thumbnailWidth);}$item.append($preview);} else {$item.attr("id", data.id);$item.append('<div class="state ready">等待上传...</div>');this.showPreview($item, data); //显示预览效果}return $item[0];},fileQueued: function (file) { //文件被添加进队列var self = this;var $item = $(this.renderItem(true, file));var $fileList = this.$elements.$fileList;$fileList.append($item); //显示在文件列表中self.loadUploadFileBtnStyle(); //加载上传按钮样式$item.on("click", 'button', function () {var $this = $(this);if($this.parents(".file-retry")[0]) {self.retryFile($item, file);} else if ($this.parents(".file-delete")[0]) {self.deleteFile($item, file, self.deleteServerFileCallback, self.$fns.removeFileWithItem);}});self.loadChooseFileBtnStyle(this.$elements.$chooseFileBtn, this.$elements.$uploadFileBtn);},fileDequeued: function (file) {this.loadUploadFileBtnStyle();},uploadProgress: function (file, percentage) { //文件上传过程中创建进度条var $item = this.getItem(file);$item.find('.file-delete, .preview-tips').addClass("uploading"); //隐藏删除按钮、提示文字$item.removeClass("retry"); //移除重试class$item.find('.progress').show(); //显示进度条var $percent = $item.find('.progress .progress-bar');$percent.css('width', percentage * 100 + '%');},uploadComplete: function (file) { //完成上传时,无论成功或者失败var $item = this.getItem(file);$item.find('.progress').fadeOut();$item.find('.file-delete, .preview-tips').removeClass("uploading"); //显示删除按钮、提示文字var $uploadFileBtn = this.$elements.$uploadFileBtn;var $chooseFileBtn = this.$elements.$chooseFileBtn;this.loadChooseFileBtnStyle($chooseFileBtn, $uploadFileBtn);this.loadUploadFileBtnStyle();},uploadSuccess: function (file, response) {// 文件上传完成后var res=JSON.parse(response._raw);//这里可以得到后台返回的数据var $item = this.getItem(file),$state = $item.find('.state');$item.find('.progress').hide();if (res.status) { //上传成功时this.uploadSuccessCallbck($item, res); //用于标识为服务端文件if (!$state.hasClass('success')) {$state.attr("class", "state success");$state.text('上传成功');}$item.removeClass("retry");} else {if (!$state.hasClass('error')) {$state.attr("class", "state error");$state.text('上传失败');}$item.addClass("retry");}},uploadSuccessCallbck: function ($item, data) { //上传文件成功时的回调,用于标识为服务端文件console.log("$item",$item)if($item && data) {var input = document.createElement("input");console.log(data.data)var data = data.datainput.type="hidden";input.name=data.id;input.value="/"+data.path;$item .append(input);}},/**** 当文件被加入队列之前触发,若返回false则此文件不会被添加进入队列* @param file* @returns {boolean} 为true时可以添加到webuploader中并进行显示*/beforeFileQueued: function(file) {var fileSize = this.fileSize; //获取当前总个数if(fileSize < 1) { //无限制个数return true;}var currentFileSize = this.getCurrentFileSize(); //当前总个数var flag = false;var edit = this.edit;if(edit) { //可编辑模式时if(currentFileSize < fileSize) {flag = true;}}//执行beforeFileQueuedCallback回调函数this.beforeFileQueuedCallback(edit, flag, file, fileSize, currentFileSize);return flag;},/*** 当文件被加入队列返回结果之前触发* @param edit 是否可编辑* @param result 是否会添加并显示* @param file --- file对象* @param fileSize --- 总文件个数* @param currentFileSize --- 当前文件个数*/beforeFileQueuedCallback: function (edit, result, file, fileSize, currentFileSize) {},/*** 当validate不通过时触发* @param type* Q_EXCEED_SIZE_LIMIT 在设置了Q_EXCEED_SIZE_LIMIT且尝试给uploader添加的文件总大小超出这个值时* Q_TYPE_DENIED 当文件类型不满足时* Q_EXCEED_NUM_LIMIT 在设置了fileNumLimit且尝试给uploader添加的文件数量超出这个值时*/errorTypeHanlder: function (type, file) {},uploadError: function (file) { //文件上传失败后console.log("uploadError")var $item = this.getItem(file),$state = $item.find('.state');if (!$state.hasClass('error')) {$state.attr("class", "state error");$state.text('上传失败');}$item.addClass("retry");this.loadUploadFileBtnStyle();this.uploadErrorAfter(file);},/*** 上传失败后执行* @param file*/uploadErrorAfter: function (file) {},uploadFinished: function () {}, //文件上传完后触发serverFileAttrName: "data-server-file", //服务端文件的属性名称getIsServerFile: function ($item) { //判断文件是否是服务端文件var val = $item && $item.attr(this.serverFileAttrName);if(val && val === "true") {return true;}return false;},getServerFileSize: function () { //获取服务端文件的个数var $fileList = this.$elements.$fileList;var size = 0;var serverFileAttrName = this.serverFileAttrName;if($fileList) {size = $fileList.find(".file-item["+serverFileAttrName+"='true']").size();}return size;},getItemSize: function () { //获取当前item的文件个数var $fileList = this.$elements.$fileList;var size = 0;if($fileList) {size = $fileList.find(".file-item").size();}return size;},getCurrentFileSize: function () { //获取当前uploader实例中文件的个数var fileStatus = WebUploaderSupport.fileStatus;var $fns = this.$fns;var initedSize = $fns.getFileSize(fileStatus.inited); //初始状态个数var errorSize = $fns.getFileSize(fileStatus.error); //上传失败个数var size = initedSize + errorSize + this.getServerFileSize();//最终加上服务端文件个数var itemSize = this.getItemSize();var result = itemSize > size ? itemSize : size;return result;},removeFileItem: function($item) { //移除$itemif($item && $item[0]) {$item.off().remove();}},deleteFile: function ($item, file, deleteServerFileCallback, removeFileWithItem) { //删除文件的处理逻辑,包含服务端if(this.getIsServerFile($item)) { //服务端时if(this.edit) {this.deleteServerFile($item, deleteServerFileCallback);} else {this.$fns.log("can't delete server file");}}else {if(removeFileWithItem && file) {removeFileWithItem(file);}var $chooseFileBtn = this.$elements.$chooseFileBtn, $uploadFileBtn = this.$elements.$uploadFileBtn;this.loadChooseFileBtnStyle($chooseFileBtn, $uploadFileBtn);}},deleteServerFileAttrName: "data-delete-url",/*** 删除服务端文件(依赖于getIsServerFile的判断结果)的业务操作,可根据实际覆盖重写(support配置中直接重写该函数即可)* @param $item* @param deleteServerFileCallback*/deleteServerFile: function ($item, deleteServerFileCallback) {var self = this;//获取删除的urlvar url = $item && $item.attr(self.deleteServerFileAttrName);if(url) {$.ajax({dataType: "json",type: "post",url: url,success: function (json) {if(deleteServerFileCallback && typeof deleteServerFileCallback === "function") {deleteServerFileCallback(self, $item, json); //通过callback执行业务操作var $chooseFileBtn = self.$elements.$chooseFileBtn, $uploadFileBtn = self.$elements.$uploadFileBtn;self.loadChooseFileBtnStyle($chooseFileBtn, $uploadFileBtn);}}});}},/*** deleteServerFile 响应成功时的回调处理,可根据实际覆盖重写* @param self 当前对象* @param $item* @param data*/deleteServerFileCallback: function (self, $item, data) {if(data.status) {self.removeFileItem($item);} else {alert(data.content);}},serverFiles: [], //加载服务端的数据,当前为 [{name:string, src: string, attrs: {}}]init: function (data, $fileList, $chooseFileBtn, $uploadFileBtn) { //初始化服务端数据,及加载样式var self = this;var edit = self.edit;var $files = null;var thumbnailHeight = self.thumbnailHeight;$fileList.css({"min-height": thumbnailHeight + 20}); //设置该区域最小高度为thumbnailHeight + 20px//加载服务端数据if(data && data.length > 0) {for(var i in data) {var item = data[i];var $item = $(this.renderItem(false, item));if(!edit) {$item.addClass("not-edit");}self.setItemStyle($item); //以缩略图大小设置$item宽高if($item && item) {var attrs = item.attrs;for(var key in attrs) { //设置$item属性值$item.attr(key, attrs[key]);}}if(i === "0") {$files = $item;} else {$files = $files.add($item);}}}if($files) { //加载服务端数据$fileList.append($files);$files.on('click', '.file-delete button', function () {var $item = $(this).parents(".file-item");self.deleteFile($item, null, self.deleteServerFileCallback);});}self.loadChooseFileBtnStyle($chooseFileBtn, $uploadFileBtn);},editChange: function (edit) { //用于根据edit改变时进行设置webuploader模式var that = this;that.edit = edit;var $chooseFileBtn = that.$elements.$chooseFileBtn, $uploadFileBtn = that.$elements.$uploadFileBtn;var $fileList = that.$elements.$fileList;if(edit) {$fileList.children().removeClass("not-edit");} else {$fileList.children().addClass("not-edit");}that.loadChooseFileBtnStyle($chooseFileBtn, $uploadFileBtn);},getChooseFileLabel: function ($chooseFileBtn) { //获取当前上传文件按钮对应的label,该label用于触发选择文件var $label = null;if($chooseFileBtn) {if($chooseFileBtn.hasClass("webuploader-container")) {$label = $chooseFileBtn.find(".webuploader-element-invisible").next("label");} else {$label = $(".webuploader-container").not(this.chooseFileBtn).find(".webuploader-element-invisible").next("label");}}return $label;},loadChooseFileBtnStyle: function ($chooseFileBtn, $uploadFileBtn) { //根据文件个数进行展示选择文件的按钮(用于上传完成时,删除文件时,添加到队列时, 初次加载服务端数据时)var that = this;var $fns = that.$fns;var fileSize = that.fileSize;var $actions = $chooseFileBtn.parents(".actions");var $actionsArea = $actions.parent(".actions-area");var $label = that.getChooseFileLabel($chooseFileBtn);if (that.edit) { //可编辑时$actionsArea.css("height", "");$actions.show();var uploader = $fns.getUploader();if(uploader) {uploader.refresh(); //解决label按钮点击无反应}if (fileSize > 0) {var currentSize = that.getCurrentFileSize();if (fileSize === currentSize) {$label && $label.hide();$chooseFileBtn.hide();$uploadFileBtn.addClass("right");} else {$label && $label.show();$chooseFileBtn.show();$uploadFileBtn.removeClass("right");}} else {$label && $label.show();$chooseFileBtn.show();$uploadFileBtn.removeClass("right");}} else { //不可编辑时$actions.hide();$actionsArea.css("height", 10);if ($label) {$label.hide();}}}};support = $.extend(support, options.support);support.$fns = $fns; //设置support方法that.supports = support;var multiple = support.multiple;delete options.support; //删除额外的support属性var $uploader = $(support.uploader),$chooseFileBtn = $uploader.find(support.chooseFileBtn), //选择文件的按钮选择器$fileList = $uploader.find(support.fileList), //显示文件列表的区域$uploadFileBtn = $uploader.find(support.uploadFileBtn), //上传文件的按钮$dndWrapper = $uploader.find(support.dndWrapper); //支持拖拽到此区域var $elements = {$uploader: $uploader,$chooseFileBtn: $chooseFileBtn,$fileList: $fileList,$uploadFileBtn: $uploadFileBtn,$dndWrapper: $dndWrapper};support.$elements = $elements;var defaultOption = {accept: {title: 'Images',extensions: 'gif,jpg,jpeg,bmp,png',mimeTypes: 'image/!*'},pick: {id: $chooseFileBtn,multiple: multiple},disableGlobalDnd: true,dnd: $dndWrapper, //支持拖拽到此区域resize: false,compress: false, //不压缩图片,原图swf: 'Uploader.swf' // swf文件路径};var currentOptions = $.extend(true, {}, defaultOption, options); //当期webuploader的配置, options中的优先级最高if(document.all || window.ActiveXObject || "ActiveXObject" in window) {if(currentOptions.paste != null) {currentOptions.paste = null;$fns.log("ie is not support paste");}}that.edit = support.edit;that.support = WebUploader.Uploader.support(); //获取是否支持webuploader上传jQuery(function() {var $ = jQuery;$fileList.css({"min-height": support.fileListHeight + 20});var uploader;try {if(!that.support) {support.init(support.serverFiles, $fileList, $chooseFileBtn, $uploadFileBtn);$fns.log("WebUploader does not support the browser you are using.");return;} else {uploader = WebUploader.create(currentOptions); //实例化webuploadersupport.instance = uploader;support.init(support.serverFiles, $fileList, $chooseFileBtn, $uploadFileBtn);}} catch (e) {if(console) {console.log(e);}}if(uploader) {that.uploader = uploader;if($uploadFileBtn && $uploadFileBtn[0]) {$uploadFileBtn.click(function () {$fns.upload();});}//文件被添加进队列时uploader.on('fileQueued', function (file) {support.fileQueued && support.fileQueued.apply(support, arguments);});//移除文件时uploader.on('fileDequeued', function (file) {support.fileDequeued && support.fileDequeued.apply(support, arguments);});uploader.on('uploadProgress', function (file, percentage) {support.uploadProgress && support.uploadProgress.apply(support, arguments);});//完成上传时,无论成功或者失败uploader.on('uploadComplete', function (file) {support.uploadComplete && support.uploadComplete.apply(support, arguments);});// 文件上传完成后,添加相应的样式(响应成功)uploader.on('uploadSuccess', function (file, data) {support.uploadSuccess && support.uploadSuccess.apply(support, arguments);});// 文件上传失败,显示上传出错(上传失败出现错误状态码时)uploader.on('uploadError', function (file) {support.uploadError && support.uploadError.apply(support, arguments);});// 当文件被加入队列之前触uploader.on('beforeFileQueued', function (file) {return support.beforeFileQueued && support.beforeFileQueued.apply(support, arguments);});//当前uploader实例文件上传完成后触发uploader.on("uploadFinished", function () {support.uploadFinished && support.uploadFinished.apply(support, arguments);});uploader.on('error', function () {support.errorTypeHanlder && support.errorTypeHanlder.apply(support, arguments);});}});}//上传该uploader实例的文件 WebUploaderSupport.prototype.upload = function () {this.$fns.upload(); } //判断是否正在上传中 WebUploaderSupport.prototype.isInProgress = function () {var flag = false;var uploader = this.uploader;if(uploader) {flag = uploader.isInProgress();}this.$fns.logInfo();return flag; }WebUploaderSupport.prototype.retry = function () {this.$fns.retry(); }WebUploaderSupport.prototype.getSupports = function () {var supports = this.supports;return supports; } //更换模式 WebUploaderSupport.prototype.editChange = function (edit) {if(typeof edit != "boolean") {throw new Error("the param type must be boolean");}var supports = this.supports;this.edit = edit;supports.editChange(edit); }
参考github上的一个朋友对webuploader 的封装:https://github.com/joker-pper/WebUploaderSupport