定制jQuery File Upload为微博式单文件上传
日志未经声明,均为AlloVince原创。版权采用『 知识共享署名-非商业性使用 2.5 许可协议』进行许可。
jQuery File Upload是一个非常优秀的上传组件,主要使用了XHR作为上传方式,并且利用了相当多的现代浏览器功能,所以可以实现诸如批量上传、超大文件上传、图片预览、拖拽上传、上传进度显示、跨域上传等功能。
美中不足的是jQuery File Upload的默认UI比较复杂,集成了全部功能,让jQuery File Upload的定制变得比较繁琐。
尝试用jQuery File Upload制作了一个类似微博图片上传的单文件式上传Demo,将一些要点记录下来备忘。最终效果如下图:

jQuery File Upload的最简模型
jQuery File Upload包含了一堆文件,首先需要弄清楚的是最核心的部分是哪些,根据官方的例子可以知道,一个最简单的jQuery File Upload上传组件,必须包括以下文件:
- jQuery核心库,建议使用jQuery 1.8以上版本
- js/vendor/jquery.ui.widget.js : jQuery UI Widget
- js/jquery.iframe-transport.js : 扩展iframe数据传输
- js/jquery.fileupload.js : jQuery File Upload核心类
- js/cors/jquery.xdr-transport.js 在IE下应载入此文件解决跨域问题
此时只需要加载一个上传按钮
<input id="fileupload" type="file" name="files[]" data-url="server/php/" multiple>
以及一行代码
$('#fileupload').fileupload();
就完成了一个最基本的上传组件。这个最简单的上传组件可以将选中的文件以表单形式提交到data-url约定的URL,同时提供了足够多的设置和基础事件可供扩展。
jQuery File Upload的简单扩展
对于最简模型,稍加扩展就可以实现一些比较常用的功能,比如可以在上传完毕后可以显示一个简单的结果:
$('#fileupload').fileupload({
done: function (e, data) {
$.each(data.result, function (index, file) {
$('<p/>').text(file.name + ' uploaded').appendTo($("body"));
});
}
});
或者显示上传进度,配合一些进度条组件就可以构成一个上传进度条
$('#fileupload').fileupload('option', {
progressall: function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
console.log(progress + '%');
}
});
等等。只要多阅读手册就可以配合项目做更具体的扩展开发。
XHR响应为Json时IE的下载BUG
这里需要特别注意的是,由于jQuery File Upload都是采用XHR在传递数据,服务器端返回的通常是JSON格式的响应,但是IE会将这些JSON响应误认为是文件传输,然后直接弹出下载框询问是否需要下载。
解决这个问题的方法是必须将相应的Http Head从
Content-Type: application/json
更改为
Content-Type: text/plain
具体的实现根据服务端不同有所区别,比如ZF2中可以在Controller中这样写:
$this->getServiceLocator()->get('Application')->getEventManager()->attach(\Zend\Mvc\MvcEvent::EVENT_RENDER, function($event){
$event->getResponse()->getHeaders()->addHeaderLine('Content-Type', 'text/plain');
}, -10000);
这也是我在stackoverflow上的对ZF2更改最终响应类型的一个回答
jQuery File Upload UI的构成与说明
为了引入更多功能,jQuery File Upload在上面最简模型的基础上又实现了一套jQuery File Upload UI,也就是官方给出的最终Demo,这套UI额外提供了以下功能:
- 最大/最小文件限定 Options.maxFileSize / Options.mixFileSize
- 文件类型限定,通过正则表达式检测文件名实现 Options.acceptFileTypes
- 选择文件后自动上传 Options.autoUpload
- 上传文件数量限制,通过上传后将选择文件按钮置为Disabled实现 Options.maxNumberOfFiles
- 上传模板,就是选择文件后显示预览的html代码 Options.uploadTemplate
- 下载模板,当文件上传完毕后显示的html代码 Options.downloadTemplate
等等,同时还增加了一系列新的接口和事件,具体都可以查阅官方手册。
具体对应到文件为:
- JavaScript-Templates : JS模板引擎
- JavaScript-Load-Image : 图片预览功能
- js/jquery.fileupload-ui.js & css/jquery.fileupload-ui.css : UI核心类,CSS可以替换旧式的上传控件为统一的按钮
- js/jquery.fileupload-fp.js:进度条扩展功能
也许正是因为附加功能太多,各功能之间耦合非常重,jQuery File Upload UI显得不够友好,主要体现在:
- 上述功能均无法拆分,必须统一全部加载
- 各功能需要界面存在相应元素,如果缺少某些元素,包括JS模板内的元素,整个UI无法正常工作
- JS模板引擎对标签配对非常严格,标签如果遗漏也有可能引起UI无法正常工作
所以经验之谈是,在定制jQuery File Upload UI时,如果UI无法工作。首先检查js文件是否全部加载,然后检查页面元素是否齐全,再次检查JS模板标签是否严格配对,最后还可以查看页面是否有重复调用fileupload()方法。
jQuery File Upload UI构成元素
UI的部件都是硬编码的HTML class,无法更改。核心的几个部件为
全局控制按钮 (必须)
<div class="fileupload-buttonbar">
<span class="fileinput-button"><input type="file" name="files[]" multiple></span>
<button type="submit" class="start">Start upload</button>
<button type="reset" class="cancel">Cancel upload</button>
<button type="button" class="delete">Delete</button>
<input type="checkbox" class="toggle">
</div>
最外层容器为.fileupload-buttonbar,内部包含
- 文件选择按钮 .fileinput-button (必须),内部必须包裹一个input:file
- 开始上传按钮 .start
- 取消上传按钮 .cancel
- 删除按钮 .delete
- 文件勾选按钮 .toggle
整体上传进度 (可选)
<div class="fileupload-progress">
<div class="progress">
<div class="bar" style="width:0%;"></div>
</div>
<div class="progress-extended"></div>
</div>
最外层容器为.fileupload-progress,内部包含
- 上传进度条容器.progress
- 上传进度条 .bar
- 上传进度文本 .progress-extended
文件显示容器 (必须)
<div class="files"></div>
.file容器是最重要的UI部件,上传时的文件预览模板以及上传完毕后的文件显示模板都将显示在这里。
文件预览模板 (必须)
<script id="template-upload" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
<div class="template-upload">
{% if (file.error) { %}
<div class="error">{%=file.error%}</div>
{% } else { %}
<div class="preview"><span class="fade"></span></div>
<div class="name"><span>{%=file.name%}</span></div>
<div class="size"><span>{%=o.formatFileSize(file.size)%}</span></div>
<div class="progress progress-success progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" style="height:5px;"><div class="bar" style="width:0%;"></div></div>
<span class="start">
{% if (!o.options.autoUpload) { %}
<button>Start Upload</button>
{% } %}
</span>
{% } %}
<span class="cancel"><button>Cancel</button></span>
</div>
{% } %}
</script>
这部分逻辑不难读懂,由于文件选择是多选的,所以被选择文件一开始以数组方式存放,循环输出。即使我们加入最大文件只能上传一个,这里得到的仍然是数组形式。
当文件有任何错误时,如文件类型被禁止,文件大小不符合约定,会得到file.error。文件检测没有问题,则可以用以下元素控制当前文件:
- 开始上传当前文件按钮.start (必须)
- 取消上传当前文件按钮.cancel (可选)
- 当前文件上传进度.progress (可选)
上传后文件回调显示模板 (必须)
<script id="template-download" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
<div class="template-download">
{% if (file.error) { %}
<div class="error">{%=file.error%}</div>
<span class="cancel"><button class="btn btn-block"><i class="icon-ban-circle"></i>Cancel</span>
{% } else { %}
<div class="preview"><img src="{%=file.thumbnail_url%}"></div>
<div class="name"><span>{%=file.name%}</span></div>
<div class="size"><span>{%=o.formatFileSize(file.size)%}</span></div>
<div class="delete"><button data-type="{%=file.delete_type%}" data-url="{%=file.delete_url%}">Delete</button>
</div>
{% } %}
</div>
{% } %}
</script>
这一部分的o.files完全来自服务器端的json响应,所以模板内容可以自由发挥。唯一被定制的元素为删除按钮.delete。 点击这个按钮会向按钮中指定的url发送请求,比如
<div class="delete"><button data-type="DELETE" data-url="/file/1">Delete</button></div>
点击后则会用DELETE方式发送HTTP请求
DELETE /file/1
jQuery File Upload UI工作流程
有了上面罗列的UI元素,就可以拼凑出一个简单的jQuery File Upload UI工作流程:
- 用户点击.fileinput-button选择要上传的文件(多个)
- 文件选择后,文件信息被整理为数组置入文件预览模板#template-upload
- 模板引擎循环处理文件信息并生成模板.template-upload
- 每生成一个模板,模板就被插入到文件显示容器.files的最后。
- 用户点击上传按钮.start上传,文件信息被转换为XHR请求至服务器端
- UI获得服务器端生成JSON响应文件
- JSON响应信息也被整理成数组置入回调显示模板#template-download
- 模板引擎循环处理文件信息并生成模板.template-download
- 每生成一个模板,会将此模板替换对应的.template-upload部分
定制过程
有了上面的基础,要个性化的定制jQuery File Upload就简单了很多:
限制文件类型
由于没有使用Flash空间,上传的文件选择框是无法限制文件类型的,所以所谓的限制文件类型,只能让用户选择文件之后,用file.error显示一个错误信息。例如本次需要限定可上传的文件为图片,那么Options指定:
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i
即可。
在Google Chrome浏览器中,可以用input:file原生支持文件类型限定,可以配合使用:
<input type="file" name="upload[]" accept="image/png, image/gif, image/jpg, image/jpeg">
不过在客户端做再多的限定也只是提升用户体验,不能真正保证安全性,所以不要忘记了在服务器端做同样的类型检测。
文件数量限制
只需在Options指定
maxNumberOfFiles : 1
即可。jQuery File Upload UI的处理方式是当用户上传一个文件后,文件选择按钮被置为Disabled。
这同样只是客户端的小把戏,真正想要严格的约束用户只能上传一个文件还是需要在服务器端通过Session做更加复杂的控制。
文件大小限制
Options中指定
maxFileSize: 5000000
即只允许单文件最大5MB。
Firefox disable bug
在Firefox环境下测试是,发现如果将文件数量限制为1,选择一次文件,刷新页面之后文件选择按钮会莫名其妙的被加上一个Disabled属性,导致无法点击。所以最终我们的初始化代码为:
var uploader = $("#fileupload");
uploader.fileupload({
dataType: 'json',
autoUpload: false,
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
maxNumberOfFiles : 1,
maxFileSize: 5000000
});
uploader.find("input:file").removeAttr('disabled');
最后就是界面的一些调整,完整代码在EvaEngine的File模块下,点击查看.
定制jQuery File Upload为微博式单文件上传的更多相关文章
- jquery file upload + asp.net 异步多文件上传
百度了很久,国内一直 找不到 使用jquery file upload 插件 +asp.net 的相关代码 一开始使用 jquery uploadify ,一款基于 flash的插件,但是不支持 Sa ...
- jquery ajax file upload NET MVC 无刷新文件上传
网上有各种各样的文件上传方法,有基于JS框架的.也有基于flash swf插件的. 这次分享一个比较简单而且实用能快速上手的文件上传方法,主要步骤: 1.引用Jquery包,我用的是jquery-1. ...
- blueImp/jQuery file upload 的正确用法(限制上传大小和文件类型)
这个插件太出名了,几乎能完成所有能想象的到的效果,包括进度条.拖拽.甚至现在已经完美支持图片视频等的处理,三个字形容就是屌爆了.最近在做上传这一部分,发现网上对于上传文件大小的限制和类型检测等的方法都 ...
- Spring Boot2(十四):单文件上传/下载,文件批量上传
文件上传和下载在项目中经常用到,这里主要学习SpringBoot完成单个文件上传/下载,批量文件上传的场景应用.结合mysql数据库.jpa数据层操作.thymeleaf页面模板. 一.准备 添加ma ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(56)-插件---单文件上传与easyui使用fancybox
系列目录 https://yunpan.cn/cZVeSJ33XSHKZ 访问密码 0fc2 今天整合lightbox插件Fancybox1.3.4,发现1.3.4版本太老了.而目前easyui 1 ...
- spring boot:单文件上传/多文件上传/表单中多个文件域上传(spring boot 2.3.2)
一,表单中有多个文件域时如何实现说明和文件的对应? 1,说明和文件对应 文件上传页面中,如果有多个文件域又有多个相对应的文件说明时, 文件和说明如何对应? 我们在表单中给对应的file变量和text变 ...
- php文件上传之单文件上传
为了简单一些,php文件跟form表单写在了一个文件里. php单文件上传----> <!DOCTYPE html> <html> <head> <me ...
- Struts2实现单文件上传
首先配置一下web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi ...
- SpringMVC单文件上传、多文件上传、文件列表显示、文件下载(转)
林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 本文详细讲解了SpringMVC实例单文件上传.多文件上传.文件列表显示.文件下载. 本文工程 ...
随机推荐
- Spark参数设置的方式
可以通过以下几种方式设置: 1)bin/spark-submit 可以直接读取conf/spark-defaults.conf文件 每一行为一个key和valuespark.master ...
- 转: 使用MinGW + Eclipse CDT进行C++开发的配置方法
使用MinGW + Eclipse CDT进行C++开发的配置方法 1 2 3 4 5 6 分步阅读 Eclipse作为开源的IDE,可以用来高效开发Java.C++.C等程序.本文介绍如何在Wind ...
- 不可不知的Python模块: collections
原文:http://www.zlovezl.cn/articles/collections-in-python/ Python作为一个“内置电池”的编程语言,标准库里面拥有非常多好用的模块.比如今天想 ...
- 用Telnet测试服务器的端口是否开通
可以用telnet测试远程服务器的端口是否开通,格式如下: telnet <server name> <port number> 例如: Telnet tserv 3389 ...
- 设置Linux中的Mysql不区分表名大小写
1. MySQL数据库的表名在Linux系统下是严格区分大小写的,在Windows系统下开发的程序移植到Linux系统下,如果程序中SQL语句没有严格按照大小写访问数据库表,就可能会出现找不到表的错误 ...
- Ant编译utf-8非法字符:/65279 解决方法
原文链接:http://blog.csdn.net/xiyuan1999/article/details/5989336 Ant编译utf-8非法字符:/65279 解决方法 使用ant编译j ...
- yii源码二 -- interfaces
path:framework/base/interfaces.php overview:This file contains core interfaces for Yii framework. in ...
- Hibernate的配置中,c3p0连接池相关配置
一.配置c3p0 1.导入 hibernate-c3po连接池包,Maven地址是:http://mvnrepository.com/artifact/org.hibernate/hibernate- ...
- Linux中磁盘分区、格式化、挂载等管理
1. 添加磁盘,查看磁盘状况 [root@db1 /]# fdisk -l Disk /dev/sda: bytes heads, sectors/track, cylinders Units = c ...
- HTTP长连接与短链接
想要充分了解HTTP长连接,需要首先知道一些基本概念: TCP连接 当网络通信时采用TCP协议时,在真正的读写操作之前,server与client之间必须建立一个连接,当读写操作完成后,双方不再需要这 ...