1、前言 javascript
文件上传是一个比较常见的功能,传统的选择方式的上传比较麻烦,须要先点击上传按钮,而后再找到文件的路径,而后上传。给用户体验带来很大问题。html5开始支持拖拽上传的须要的api。nodejs也是一个最近愈来愈流行的技术,这也是本身第一次接触nodejs,在nodejs开发中,最经常使用的开发框架之一是expess,它是一个相似mvc模式的框架。结合html五、nodejs express实现了拖拽上传的功能。 html
2、基础知识普及 前端
一、NodeJs基础知识 html5
nodejs简单来讲就是一个可让js在服务端也能运行的开发平台,nodejs发展很是很快,不少国内公司也已经开始使用好比淘宝等。传统的web应用程序开发平台依靠多线程来实现高并发请求的响应。而nodejs采用了单线程、异步式IO、事件驱动的设计模型,给nodejs带来了巨大的性能提高。这也是nodejs最大的特色,在nodejs中,全部的IO操做都是经过回调的方式进行,nodejs在执行IO操做时会把IO请求推送一个事件队列,等待程序进行处理,等处理完IO,而后调用回调函数返回结果。 java
好比在查询数据库操做以下: node
mysql.query("SELECT * FROM myTable",function(res){ callback(res); });
在以上代码中,nodejs在执行以上语句时,不会等待数据库返回结果,而是继续执行后面的语句。在数据库获取到数据后,会发送到事件循环队列中,等到线程进入事件循环队列后,才执行callback的东西。 mysql
关于nodejs更多的知识,我也知识看了两天,了解很少。了解更多的知识能够在网络上搜索。 jquery
nodejs入门的知识 http://www.nodebeginner.org/index-zh-cn.html http://blog.jobbole.com/17174/ git
二、express基础知识 github
nodejs是一个比较活跃的开源社区,它拥有大量的第三方开发库,其中Express是其中最普遍的、最经常使用的框架之一。也是nodejs官方推荐的框架。它除了对常见http操做的封装,还实现了路由控制、模版解析支持、动态试图、用户回话等等。但它也不是一个万能的框架,绝大多数功能是对http的封装,它只是一个轻量级的框架。不少功能还须要集成第三方库还实现。
exress提供了很是方便的上传功能的支持,在文件上传请求之后,express会接收文件并把文件存在一个临时目录,而后在路由到的方法中,咱们只需把文件从临时目录下拷贝到咱们要存放用户上传文件夹便可。在文件上传部分,服务器端的实现就是基于express这个功能来实现的。
三、html5拖曳上传api
html5提供不少新的特性,拖拽事件以及文件上传就是新特性之一。因为篇幅有限,后面重点介绍拖曳上传的代码实现。就不一一列出html5提供的拖曳上传的apil了,感兴趣的能够参考:http://w3school.com.cn/html5/html5_ref_eventattributes.asp#Mouse_Events http://wen866595.iteye.com/blog/1898236
3、拖曳上传实现
一、代码实现
先来看下前端js的文件目录:
其中:
uploader.js主要实现对html5支持的上传功能的封装。
uploaderQueue.js主要实现上传文件队列的管理,以及文件上传对象,把文件队列中的文件上传到服务器。
uploaderApp.js主要文件上传的入口,主要实现上传窗口对拖曳事件的监听并把拖曳文件推动上传文件队列,启动文件上传程序。
下面对核心代码(须要)作简单的解释,全都代码能够到这里下载:FileUploader
首先对html5提供的文件上传作简单的封装uploader.js
var uploaderFactory = { send: function (url, data, files, callback) { var insUploader = new uploader(url, data, files); insUploader.callback = function (status, resData) { if (typeof callback === 'function') { callback(status, resData); } } insUploader.send(); return insUploader; } };
uploader对象主要是对html5提供的原生api进行简单的封装。uploaderFactory提供一个简单的接口,使用它能够像jquery的ajax方法同样完成,文件上传调用。html5中提供的文件上传的支持,是在原来XMLHttpRequest基础之上扩展一些属性和方法,提供了FormData对象,来支持文件上传操做。
文件上传队列(uploaderQueue.js)也是一个比较重要的对象,它包括两个对象一个是Queue,文件队列对象,主要负责管理文件队列的增删改查询等操做,另外一个对象是UploadEngine,文件上传引擎,它的功能主要是负责从文件队列中取出文件对象,调用uploader对象上传文件,而后更新文件队列中的文件状态。Queue以及UploadEngine都是单例对象。
首先来看下文件队列对象:
上传文件队列使用一个数组管理每一个文件对象信息,每一个文件对象有key,data,status三个属性,该对象主要负责文件对象的增长、删除、更新、查找的功能。
上传文件队列中另外一个比较重要的对象是上传引擎对象(uploadEngine.js)
该对象比较简单主要提供一个run以及setUrl方法,用于启动上传引擎,以及设置上传路径的功能。内部使用递归的方法把文件队列中的方法所有上传到服务端。使用uploadItemProgress通知外部上传的进度,使用uploadStatusChanged通知文件上传状态,以便更新UI.
uploaderApp.js中主要包括三个对象,一个是相似jquery的一个简单的jquery对象(App$)。主要用于绑定事件。一个是uploaderArea对象,是拖曳上传的窗口区域,另外一个是入口对象uploaderMain对象。主要用于初始化对象,对外部提供一个init方法,来初始化整个对象。
了解关于App$以及uploaderArea对象的代码请下载源代码,下面仅对uploaderMain对象作简单的说明。
(function (app) { var _self; function uploaderMain(id) { this._id = id; this._area = null; this.uploaders = []; this._URL = 'file/uploader'; } uploaderMain.prototype = { init: function () { _self = this; this._initArea(); this._initQueueEng(); }, _initQueueEng: function () { uploaderQueue.Engine.setUrl(this._URL); uploaderQueue.Engine.uploadStatusChanged = function (key, status) { if (status === uploaderQueue.UploadStatus.Uploading) { _self._area.hideItemCancel(key); } else if (status === uploaderQueue.UploadStatus.Complete) { _self._area.completeItem(key); _self._area.showItemCancel(key); } } uploaderQueue.Engine.uploadItemProgress = function (key, e) { var progress = e.position / e.total; _self._area.changeItemProgress(key, Math.round(progress * 100)); } }, _initArea: function () { this._area = new app.area(this._id); this._area.init(); this._area.drop = function (e) { var key = uploaderQueue.Queue.add({files: e.dataTransfer.files}); uploaderQueue.Engine.run(); return key; } this._area.cancelItem = function (key) { uploaderQueue.Queue.remove(key); } } }; app.main = uploaderMain; })(window.uploaderApp);
在uploaderMain对象,至关于各个对象之间的中介,主要就是作对象的初始化功能、以及对象之间相互调用。使各个对象之间相互协做完成整个模块的功能。对外提供一个init方法来初始化整个程序,在html页面中只需以下代码:
<script type="text/javascript"> var main=new uploaderApp.main('container'); main.init(); </script>
以上代码就是建立一个入口对象,而后使用init方法来启动整个程序。
以上是对前端js的主要方法作的简单解释,若是想详细了解请下载源代码。下面简单看下后端js(nodejs)端实现的主要代码。
在express基础知识时,已经讲过在express已经对文件上传功能作了完整的封装,当路由到action时,文件已经完成上传只是文件上传到了一个临时目录,这个临时目录咱们能够在app.js中配置的,配置方式以下:
app.use(express.bodyParser({ uploadDir:__dirname+'/public/temp' }));
这样在文件上传后文件就存放在/public/temp目录下,文件名也是express经过必定的算法随机获取的。在咱们写的action中只须要把存在临时目录中的文件移动到服务端存放文件的目录下,而后删除临时目录下的文件便可。具体代码以下:
function uploader(req, res) { if (req.files != 'undifined') { console.dir(req.files); utils.mkDir().then(function (path) { uploadFile(req, res, path, 0); }); } } function uploadFile(req, res, path, index) { var tempPath = req.files.file[index].path; var name = req.files.file[index].name; if (tempPath) { var rename = promise.denodeify(fs.rename); rename(tempPath, path + name).then(function () { var unlink = promise.denodeify(fs.unlink); unlink(tempPath); }).then(function () { if (index == req.files.file.length - 1) { var res = { code: 1, des: '上传成功' }; res.send(res); } else { uploadFile(req, res, path, index + 1); } }); } }
二、实现效果
4、获取代码