深入学习jquery源码之上传附件插件的实现
/**
* 上传附件通用JS (基于layerUI)
*/
;(function($){
var defaults = {
url : "/attach/upload",
fieldCode : "aboutDocument", //业务字段编码
fieldName : "相关文件", //业务字段名称
entityName : "template", //业务实体
};
function renderUpload(options){
this.settings = $.extend({},defaults,options);
this.settings.elem = "#" + this.settings.fieldCode;
this.settings.bindAction = "#" + this.settings.fieldCode + "_Action"; //上传操作按钮
this.settings.layuiUploadPreview = "#"+ this.settings.fieldCode +"_preview";
this.settings.previewTableBody = "#"+ this.settings.fieldCode +"_Preview_Table"; //上传预览表格
this.init();
}
//为函数添加原型链上的方法
renderUpload.prototype = {
init: function(){
var that = this;
var uploadInst = layui.upload.render({
elem: that.settings.elem //绑定元素
,url: CONTEXT_PATH + that.settings.url //上传接口
,accept:'file'
,data:{ //上传参数
"entityName" : that.settings.entityName, //业务实体
"fieldCode" : that.settings.fieldCode, //业务字段编码
"fieldName" : that.settings.fieldName, //业务字段名称
}
,auto:false //是否选完文件后自动上传 如果设定 false,那么需要设置 bindAction 参数来指向一个其它按钮提交上传
,size:0 //设置文件最大可允许上传的大小,单位 KB。不支持ie8/9; 0(即不限制)
,multiple:true
//是否允许多文件上传。设置 true即可开启。不支持ie8/9
,bindAction: that.settings.bindAction //指向一个按钮触发上传,一般配合 auto: false 来使用。值为选择器或DOM对象,如:bindAction: '#btn'
,choose: function(res){ //选择文件后的回调函数
var layIndex = layer.open({
type: 1,
title: "预览",
maxmin: false,
area : ['40%', '40%'],
content:$(that.settings.layuiUploadPreview).removeAttr('style'), //$.loadHtml(preUrl),
success: function(layero){
var demoListView = $(that.settings.previewTableBody).empty();
var files = that.settings.selfFiles = res.pushFile(); //将每次选择的文件追加到文件队列
//读取本地文件
res.preview(function(index, file, result){
var tr = $(['<tr id="upload-'+ index +'">'
,'<td>'+ file.name +'</td>'
,'<td>'+ (file.size/1024).toFixed(1) +' kb</td>'
,'<td name="upload-status">等待上传</td>'
,'<td>'
,'<button class="layui-btn layui-btn-mini demo-reload layui-hide">重传</button>'
,'<button class="layui-btn layui-btn-mini layui-btn-danger demo-delete">删除</button>'
,'</td>'
,'</tr>'].join(''));
//单个重传
tr.find('.demo-reload').on('click', function(){
res.upload(index, file);
});
//删除
tr.find('.demo-delete').on('click', function(){
delete files[index]; //删除对应的文件
tr.remove();
uploadInst.config.elem.next()[0].value = ''; //清空 input file 值,以免删除后出现同名文件不可选
if(Object.getOwnPropertyNames(files).length == 0){ //当上传预览没有文件时,关闭弹出框
layer.close(layIndex);
}
});
demoListView.append(tr);
});
},
end : function(){ //layer销毁回调
$(that.settings.layuiUploadPreview).attr('style','display:none;');
$(that.settings.previewTableBody).empty();
},
cancel: function(){ //右上角关闭回调
}
});
}
,before: function(res){ //文件提交上传前的回调
$("tr",$(that.settings.previewTableBody)).find("td[name='upload-status']").text("上传中...");
}
,done: function(res, index, upload){ //执行上传请求后的回调。返回三个参数,分别为:res(服务端响应信息)、index(当前文件的索引)、upload(重新上传的方法,一般在文件上传失败后使用)
//上传完毕回调 "dealPicture_list_table"
if(res && res.status == WebConst.SUCCESS){
$(that.settings.bindAction).text("").text("上传成功");
delete that.settings.selfFiles[index];
//改变预览状态,将上传附件id存在 隐藏域中
$("tr[id='upload-"+ index +"']",$(that.settings.previewTableBody)).find("td[name='upload-status']").text("附件缓存完毕,请点击提交上传附件");
var unupload = $("#uploadAttachmentIds").data("uploadAttachmentIds");
if(unupload){
unupload.push(res.data['attachmentId']);
$("#uploadAttachmentIds").data("uploadAttachmentIds",unupload);
}else{
if(res.data){
$("#uploadAttachmentIds").data("uploadAttachmentIds",[res.data['attachmentId']]);
/**
* 第一个方法赋不了值,通过下面的赋值
*/
$("#uploadAttachmentIds").val([res.data['attachmentId']]);
}
}
//处理卡片页面列表展示问题
var afile = res.data;
var attachImg = "";
if(!$.isEmptyStr(afile.fileName) && (afile.fileName.indexOf('docx')!=-1
|| afile.fileName.indexOf('doc')!=-1))
{
//attachImg = '<td><img src="' + CONTEXT_PATH +"platform/common/images/word.png" /></td>';
attachImg = '<td><img src="'+CONTEXT_PATH+ '/platform/common/images/word.png"' +'width="100" height="60" style="cursor:pointer;"/></td>';
}
else if(!$.isEmptyStr(afile.fileName) && afile.fileName.indexOf('pdf')!=-1)
{
attachImg = '<td><img src="'+CONTEXT_PATH+ '/platform/common/images/pdf.png"' +'width="100" height="60" style="cursor:pointer;"/></td>';
}
else
{
attachImg = '<td><img src="' + CONTEXT_PATH + '/attach/showPicture?attachmentId='
+ afile.attachmentId + '&isThumbnail=true" max-width="120" width="100" height="60" style="cursor:pointer;"/></td>';
}
var $tr = $(['<tr id="upload-'+ afile.attachmentId +'" attatchmentId="'+ afile.attachmentId +'">'
, attachImg
,'<td>'+ afile.fileName +'</td>'
,'<td>'+ afile.fileSize +' kb</td>'
,'<td>'+ afile.createDate +'</td>'
,'<td>'
,'<a class="layui-btn layui-btn-mini demo-reload" href="'+ CONTEXT_PATH +'/attach/download?attachmentId='+ afile.attachmentId +'">下载</a> '
,'<button class="layui-btn layui-btn-mini layui-btn-danger">删除</button>'
,'</td>'
,'</tr>'].join(''));
$tr.find('button').on('click',function(){
var attId = $(this).closest("tr").attr('attatchmentId');
var url = CONTEXT_PATH + '/attach/delete/datafile';
var rlt = $.getData(url,{'attachmentIds':attId});
if(rlt && rlt.status == WebConst.SUCCESS){
$(this).closest("tr").remove();
$("#uploadAttachmentIds").data("uploadAttachmentIds").removeByValue(attId);
}
return false;
});
$("#" + afile.fieldCode + "_list_table").append($tr);
}
}
,error: function(index, upload){ //执行上传请求出现异常的回调(一般为网络异常、URL 404等)。返回两个参数,分别为:index(当前文件的索引)、upload(重新上传的方法)
//请求异常回调
}
});
}
}
//扩展jquery类方法
$.extend({
renderUpload : function(options){
return new renderUpload(options);
}
});
})(jQuery);
如何使用:
html
<@uploadPlugin fieldCode="dealPicture" fieldName="封面图片" editable="${edited}">
</@uploadPlugin>
freemarker的后台配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<!-- 自动扫描 -->
<context:component-scan base-package="com.**.controller">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<!-- <mvc:annotation-driven /> -->
<!-- 静态资源 开始 -->
<mvc:resources location="/404Error.html" mapping="/404Error.html"/>
<mvc:resources location="/view/**" mapping="/view/**"/>
<mvc:resources location="/application/**" mapping="/application/**"/>
<mvc:resources mapping="/platform/**" location="/platform/,classpath:/platform/" />
<mvc:resources mapping="/favicon.ico" location="/favicon.ico,classpath:/favicon.ico" />
<!-- 静态资源 结束 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<mvc:exclude-mapping path="/" />
<mvc:exclude-mapping path="/login" />
<mvc:exclude-mapping path="/loginCheck" />
<mvc:exclude-mapping path="/view/**" />
<mvc:exclude-mapping path="/platform/**" />
<mvc:exclude-mapping path="/application/**" />
</mvc:interceptor>
</mvc:interceptors>
<!-- jsp 视图解析-->
<bean id="jspResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 -->
<property name="contentType" value="text/html;charset=UTF-8"/>
<property name="prefix" value="/" />
<property name="suffix" value=".jsp" />
<property name="order" value="1"/>
</bean>
<!-- freemarker的配置 -->
<bean id="freemarkerConfigurer" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPaths">
<list>
<value>/view</value>
</list>
</property>
<property name="defaultEncoding" value="UTF-8" />
<property name="freemarkerVariables">
<map>
<entry key="downSelector" value-ref="downSelectorDirective"/>
<entry key="checkBox" value-ref="checkBoxDirective"/>
<entry key="redioBox" value-ref="redioBoxDirective"/>
<entry key="popSelector" value-ref="popSelectorDirective"/>
<entry key="uploadPlugin" value-ref="uploadPluginDirective"/>
</map>
</property>
<property name="freemarkerSettings">
<props>
<prop key="template_update_delay">10</prop>
<prop key="locale">zh_CN</prop>
<prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
<prop key="date_format">yyyy-MM-dd</prop>
<prop key="number_format">#.##</prop>
</props>
</property>
</bean>
<bean id="freemarkerResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="true" />
<property name="suffix" value=".html" />
<property name="order" value="0"/>
<property name="contentType">
<value>text/html;charset=UTF-8</value>
</property>
<property name="viewClass">
<value>com.framework.web.view.CntenFreeMarkerView</value>
</property>
<property name="requestContextAttribute" value="rc"></property>
</bean>
<!-- 配置文件上传,如果没有使用文件上传可以不用配置,当然如果不配,那么配置文件中也不必引入上传组件包 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 默认编码 -->
<property name="defaultEncoding" value="UTF-8" />
<!-- 文件大小最大值 -->
<property name="maxUploadSize" value="10485760000" />
<!-- 内存中的最大值 -->
<property name="maxInMemorySize" value="40960" />
</bean>
</beans>
import java.io.IOException;
import java.io.Writer;
import java.util.Map;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import freemarker.core.Environment;
import freemarker.template.SimpleScalar;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
/**
* 附件上传组件
* @author Administrator
*/
@Component
public class UploadPluginDirective implements TemplateDirectiveModel{
@Override
public void execute(Environment env, @SuppressWarnings("rawtypes") Map params, TemplateModel[] loopVars,
TemplateDirectiveBody body) throws TemplateException, IOException {
SimpleScalar fieldCode = (SimpleScalar) params.get("fieldCode"); //上传附件编码
SimpleScalar fieldName = (SimpleScalar) params.get("fieldName"); //上传附件名称
SimpleScalar editable = (SimpleScalar) params.get("editable");
Writer out = env.getOut();
if (fieldCode != null && fieldName != null) {
StringBuilder builder = new StringBuilder();
builder.append("<!-- 文件上传 开始 -->");
builder.append("<div class='layui-form-item layui-form-text'>")
.append(" <label class='layui-form-label fwb'>").append(fieldName).append("</label>")
.append(" <div class='layui-input-block'>");
if(editable != null && StringUtils.isEmpty(editable.getAsString())) {
builder.append(" <button type='button' class='layui-btn' id='").append(fieldCode).append("'>")
.append(" <i class='layui-icon'></i>上传图片")
.append(" </button>");
}
builder.append(" <div class='layui-upload' id='").append(fieldCode).append("_list'>")
.append(" <div class='layui-upload-list'>")
.append(" <table class='layui-table'>")
.append(" <thead>")
.append(" <tr><th width='25%'>缩略图</th>")
.append(" <th width='30%'>文件名</th>")
.append(" <th width='10%'>文件大小</th>")
.append(" <th width='25%'>上传时间</th>")
.append(" <th width='20%'>操作</th>")
.append(" </tr></thead>")
.append(" <tbody id='").append(fieldCode).append("_list_table'></tbody>")
.append(" </table>")
.append(" </div>")
.append(" </div>")
.append(" </div>")
.append("</div>")
.append("<!-- 文件预览 开始 -->")
.append("<div class='layui-upload' id='").append(fieldCode).append("_preview'").append(" style='display:none;'>")
.append(" <div class='layui-upload-list'>")
.append(" <table class='layui-table'>")
.append(" <thead>")
.append(" <tr><th>文件名</th>")
.append(" <th>大小</th>")
.append(" <th>状态</th>")
.append(" <th>操作</th>")
.append(" </tr></thead>")
.append(" <tbody id='").append(fieldCode).append("_Preview_Table'").append(" ></tbody>")
.append(" </table>")
.append(" </div>")
.append(" <button type='button' class='layui-btn' id='").append(fieldCode).append("_Action' ").append(">开始上传</button>")
.append("</div> ")
.append("<!-- 文件预览 结束 -->")
.append("<!-- 文件上传 结束 -->");
out.write(builder.toString());
}else {
out.write("freemarker自定义命令初始化参数缺失...");
}
if(body != null) {
body.render(out);
}else {
throw new RuntimeException("freemarker自定义标签内部至少要加一个空格");
}
}
}
js 执行实例调用附件上传
//执行实例
$.renderUpload({
fieldName : "上传附件", //业务字段名称
fieldCode : "dealPicture", //业务字段编码
entityName : "add", //业务实体
selfFiles : _self.files
});
var ShowNews = CardPager.extend({
init: function(filter, url){
this._super(filter, url);
//界面需要引用的插件
this.plugins = ['element', 'form', 'layedit', 'upload', 'laydate', 'layer'];
this.primaryKey = "newsId";
this.primaryValue = $.QueryString("entityId");
this.dataUrl = CONTEXT_PATH + '/gasNews/get';
this.entityName = "news";
},
initLayuiPlugin: function(){
this._super();
var _self = this;
_self.files = null;
//执行实例
$.renderUpload({
fieldName : "上传附件", //业务字段名称
fieldCode : "dealPicture", //业务字段编码
entityName : "news", //业务实体
selfFiles : _self.files
});
},
initEvent: function(){
this._super();
var _self = this;
//TODO 父类只定义了 保存事件,其他事件在这里进行定义
},
initThirdPlugin: function(){
var _self = this;
KindEditor.ready(function(K) {
_self.gasNewsContent = K.create('#newsContent');
});
}
});
$(function(){
showNews = new ShowGasNews('news', CONTEXT_PATH + '/news/save');
showNews.render();
//关闭卡片页面之前回调
function beforeClose (){
//如果涉及到文件上传,关闭卡片页面将未上传的附件进行删除
var unuploadFiles = $("#uploadAttachmentIds").data("uploadAttachmentIds");
if(unuploadFiles && unuploadFiles.length>0){
var url = CONTEXT_PATH + '/attach/delete/datafile';
$.getData(url,{'attachmentIds':unuploadFiles.join(",")});
}
}
});
查看图片回显
(function(scope){
var CardPager = Class.extend({
init: function(filter, url){
this.filter = filter;
this.url = url;
},
render: function(){
var _self = this;
_self.initThirdPlugin(); //初始化第三放插件
//plugins 这个可以不传,但是请不要传空数组过来
var plugins = _self.plugins || ['form'];
layui.use(plugins,function(){
_self.initEvent();
_self.initLayuiPlugin(); //初始化layui组件
//渲染表单数据
var params = {};
params[_self.primaryKey] = _self.primaryValue;
$.ajaxReq(_self.dataUrl, params, function(data){
if(data && data.status == WebConst.SUCCESS && data.data){
var cardForm = $("#"+_self.filter+"Form"),
formDoms = cardForm[0];
cardForm.setValues(data.data);
//处理富文本赋值问题
for(i=0,len=formDoms.length; i<len; i++){
var idom = formDoms[i],
idomName = idom.name,
tagName = idom.tagName,
idomId = idom.id,
keditor = _self[idomName];
if(idom.tagName == "TEXTAREA" && keditor){
keditor.html(data.data[idomName]);
}
}
layui.form.render();
}
},WebConst.AJAX_FORM,null,false);
});
_self.initFiles();
},
//附件上传查看图片回显
initFiles: function(){
var _self = this,
attachParam = {};
attachParam.entityId = _self.primaryValue;
attachParam.entityName = _self.entityName;
$.ajaxReq(CONTEXT_PATH + "/attach/entity/files", attachParam, function(data){
if(data && data.status == WebConst.SUCCESS && data.data){
var files = data.data;
$("div[class='layui-upload']").each(function(index,obj){
var containerId = $(obj).attr('id'),
attachField = containerId.split("_")[0],
tableBody = containerId + "_table";
for(var i=0,len=files.length; i<len; i++){
var cFile = files[i];
if(cFile.fieldCode == attachField){
var $tr = $(['<tr id="upload-'+ cFile.attachmentId +'" attatchmentId="'+ cFile.attachmentId +'">'
,'<td><img src="' + CONTEXT_PATH + '/attach/showPicture?attachmentId='
+ cFile.attachmentId + '&isThumbnail=true" width="100" height="60" style="cursor:pointer;"/></td>'
,'<td>'+ cFile.fileName +'</td>'
,'<td>'+ cFile.fileSize +' kb</td>'
,'<td>'+ cFile.createDate +'</td>'
,'<td>'
,'<a class="layui-btn layui-btn-mini demo-reload" href="'+ CONTEXT_PATH +'/attach/download?attachmentId='+ cFile.attachmentId +'">下载</a> '
,'<button class="layui-btn layui-btn-mini layui-btn-danger">删除</button>'
,'</td>'
,'</tr>'].join(''));
$tr.find('button').on('click',function(){
var rlt = $.getData(CONTEXT_PATH + "/attach/delete/updflag",{'attachmentId':$(this).closest("tr").attr('attatchmentId')});
if(rlt && rlt.status == '1000'){
$(this).closest("tr").remove();
}
return false;
});
$("#" + tableBody).append($tr);
}
}
})
}
},WebConst.AJAX_FORM,null,false);
},
initThirdPlugin: function(){
},
initLayuiPlugin: function(){
var _self = this;
},
initEvent: function(){
var _self = this;
layui.form.on('submit(' + _self.filter + ')', function(data){
//处理 KindEditor 富文本取值问题
var formDoms = data["form"];
for(i=0,len=formDoms.length; i<len; i++){
var idom = data["form"][i],
idomName = data["form"][i].name,
tagName = idom.tagName,
idomId = data["form"][i].id,
keditor = _self[idomName];
if(idom.tagName == "TEXTAREA" && keditor){
keditor.sync();
data.field[idomName] = $('#'+idomId ).val(); // jQuery
}
}
var retData = $.getData(_self.url, data.field);
if(retData.status == WebConst.FAIL){
layer.msg('保存失败', {icon: 5});
return false;
}
//如果有附件,上传附件
var uploadAttachmentIds = $("#uploadAttachmentIds").data("uploadAttachmentIds"),
entityId = retData.data;
$("input[name='"+ _self.primaryKey +"']").val(retData.data);
if(true && uploadAttachmentIds && entityId){
var params = {};
params.attachmentIds = uploadAttachmentIds.join(",");
params.entityId = entityId;
$.getData(CONTEXT_PATH + "/attach/updateEntityId", params);
}
$("#uploadAttachmentIds").data("uploadAttachmentIds",null);
layer.msg('保存成功', {icon: 6});
return false;
});
}
});
scope.CardPager = CardPager;
})(window);
标签:jquery,function,插件,上传,self,源码,var,data,append From: https://blog.51cto.com/u_11837698/6081932