Nodejs express、html5实现拖拽上传(转载)

一、前言

文件上传是一 个比较常见的功能,传统的选择方式的上传比较麻烦,需要先点击上传按钮,然后再找到文件的路径,然后上传。给用户体验带来很大问题。html5开始支持拖 拽上传的需要的api。nodejs也是一个最近越来越流行的技术,这也是自己第一次接触nodejs,在nodejs开发中,最常用的开发框架之一是 expess,它是一个类似mvc模式的框架。结合html5、nodejs express实现了拖拽上传的功能。

二、基础知识普及

1、NodeJs基础知识

nodejs简单来说就是一个可以让js在服务端也能运行的开发平 台,nodejs发展非常很快,很多国内公司也已经开始使用比如淘宝等。传统的web应用程序开发平台依靠多线程来实现高并发请求的响应。而nodejs 采用了单线程、异步式IO、事件驱动的设计模型,给nodejs带来了巨大的性能提升。这也是nodejs最大的特点,在nodejs中,所有的IO操作 都是通过回调的方式进行,nodejs在执行IO操作时会把IO请求推送一个事件队列,等待程序进行处理,等处理完IO,然后调用回调函数返回结果。

比如在查询数据库操作如下:

mysql.query("SELECT * FROM myTable",function(res){
              callback(res);
});

在以上代码中,nodejs在执行以上语句时,不会等待数据库返回结果,而是继续执行后面的语句。在数据库获取到数据后,会发送到事件循环队列中,等到线程进入事件循环队列后,才执行callback的东西。

关于nodejs更多的知识,我也知识看了两天,了解不多。了解更多的知识可以在网络上搜索。

nodejs入门的知识 http://www.nodebeginner.org/index-zh-cn.html  http://blog.jobbole.com/17174/

2、express基础知识

nodejs是一个比较活跃的开源社区,它拥有大量的第三方开发库,其中Express是其中最广泛的、最常用的框架之一。也是nodejs官方推荐的 框架。它除了对常见http操作的封装,还实现了路由控制、模版解析支持、动态试图、用户回话等等。但它也不是一个万能的框架,绝大多数功能是对http 的封装,它只是一个轻量级的框架。很多功能还需要集成第三方库还实现。

exress提供了非常方便的上传功能的支持,在文件上传请求以后,express会接收文件并把文件存在一个临时目录,然后在路由到的方法中,我们只 需把文件从临时目录下拷贝到我们要存放用户上传文件夹即可。在文件上传部分,服务器端的实现就是基于express这个功能来实现的。

3、html5拖曳上传api

html5提供很多新的特性,拖拽事件以及文件上传就是新特性之一。由于篇幅有限,后面重点介绍拖曳上传的代码实现。就不一一列出html5提供的拖曳上传的apil了,感兴趣的可以参考:http://w3school.com.cn/html5/html5_ref_eventattributes.asp#Mouse_Events     http://wen866595.iteye.com/blog/1898236

三、拖曳上传实现

1、代码实现

先来看下前端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都是单例 对象。

首先来看下文件队列对象:

(function (upladerQueue) {

    var Status = {
        Ready: 0,
        Uploading: 1,
        Complete: 2
    }

    var _self = null;

    var instance = null;

    function Queue() {
        this._datas = [];
        this._curSize = 0;//当前长度

        _self = this;
    }

    Queue.prototype = {
        add: function (data) {
            var key = new Date().getTime();
            this._datas.push({key: key, data: data, status: Status.Ready});
            this._curSize = this._datas.length;
            return key;
        },
        remove: function (key) {
            var index = this._getIndexByKey(key);
            this._datas.splice(index, 1);
            this._curSize = this._datas.length;
        },
        get: function (key) {
            var index = this._getIndexByKey(key);
            return index != -1 ? this._datas[index].data : null;
        },
        clear: function () {
            this._datas = [];
            this._curSize = this._datas.length;
        },
        size: function () {
            return this._curSize;
        },
        setItemStatus: function (key, status) {
            var index = this._getIndexByKey(key);
            if (index != -1) {
                this._datas[index].status = status;
            }
        },
        nextReadyingIndex: function () {
            for (var i = 0; i < this._datas.length; i++) {
                if (this._datas[i].status == Status.Ready) {
                    return i;
                }
            }
            return -1;
        },
        getDataByIndex: function (index) {
            if (index < 0) {
                return null;
            }
            return this._datas[index];
        },
        _getIndexByKey: function (key) {
            for (var i = 0; i < this._datas.length; i++) {
                if (this._datas[i].key == key) {
                    return i;
                }
            }
            return -1;
        }
    };

    function getInstace() {
        if (instance === null) {
            instance = new Queue();
            return instance;
        } else {
            return instance;
        }
    }

    upladerQueue.Queue = getInstace();
    upladerQueue.UploadStatus = Status;
})(window.uploaderQueue);

上传文件队列使用一个数组管理每个文件对象信息,每个文件对象有key,data,status三个属性,该对象主要负责文件对象的增加、删除、更新、查找的功能。

上传文件队列中另一个比较重要的对象是上传引擎对象(uploadEngine.js)

(function (upladerQueue) {

    var instance = null;
    var _self;

    function uploadEngine() {
        this._url = null;
        this._curUploadingKey = -1;//标志
        this.uploadStatusChanged = {};
        this.uploadItemProgress={};
        _self = this;
    }

    uploadEngine.prototype = {
        setUrl: function (url) {
            this._url = url;
        },
        run: function () {
            if (this._curUploadingKey === -1 && this._url) {
                this._startUpload();
            }
        },
        _startUpload: function () {
            _self = this;
            var index = upladerQueue.Queue.nextReadyingIndex();
            if (index != -1) {
                this._uploadItem(index);
            } else {
                this._curUploadingKey = -1;
                return null;
            }
        },
        _uploadItem: function (index) {
            var data = upladerQueue.Queue.getDataByIndex(index).data;
            _self = this;
            this._readyUploadItem(index);
            var upload = uploaderFactory.send(this._url, null, data.files, function (status, data) {
                _self._completedUploadItem.call(_self, status, data);
            });

            this._uploadItemProgress(upload);
        },
        _uploadItemProgress: function (upload) {
            upload.onprogress = function (e) {
               _self.uploadItemProgress(_self._curUploadingKey,e);
            }
        },
        _readyUploadItem: function (index) {
            this._curUploadingKey = upladerQueue.Queue.getDataByIndex(index).key;
            if (typeof this.uploadStatusChanged === ‘function‘) {
                this.uploadStatusChanged(this._curUploadingKey, upladerQueue.UploadStatus.Uploading);
            }
            upladerQueue.Queue.setItemStatus(this._curUploadingKey, upladerQueue.UploadStatus.Uploading);
        },
        _completedUploadItem: function (status, data) {
            if (typeof this.uploadStatusChanged === ‘function‘) {
                this.uploadStatusChanged(this._curUploadingKey, upladerQueue.UploadStatus.Complete);
            }
            upladerQueue.Queue.setItemStatus(this._curUploadingKey, upladerQueue.UploadStatus.Complete);
            this._startUpload();
        }
    };

    function getInstace() {
        if (instance === null) {
            instance = new uploadEngine();
        }
        return instance;
    }

    upladerQueue.Engine = getInstace();
})(window.uploaderQueue);

该对象比较简单主要提供一个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);
                }
            });
    }
}

2、实现效果

时间: 2024-11-10 10:52:21

Nodejs express、html5实现拖拽上传(转载)的相关文章

Nodejs express、html5实现拖拽上传

Nodejs express.html5实现拖拽上传 一.前言 文件上传是一个比较常见的功能,传统的选择方式的上传比较麻烦,需要先点击上传按钮,然后再找到文件的路径,然后上传.给用户体验带来很大问题.html5开始支持拖拽上传的需要的api.nodejs也是一个最近越来越流行的技术,这也是自己第一次接触nodejs,在nodejs开发中,最常用的开发框架之一是expess,它是一个类似mvc模式的框架.结合html5.nodejs express实现了拖拽上传的功能. 二.基础知识普及 1.No

[开源应用]利用HTML5+resumableJs拖拽上传大文件

前言: 大文件传输一直是技术上的一大难点.文件过大时,一些性提交所有的内容进内存是不现实的.大文件带来问题还有是否支持断点传输和多文件同时传输. 本文以resumableJs为例,介绍了如何在ASP.NET中实现大文件传输.同时本文利用了Html5的新特性:支持拖拽. 本文的主要技术点在于:如何接收resumableJs的传送内容(官网不太清楚)和如何合并文件,难度并不高. 注:原博客中,此文章为原站点个人代码备份所用,注释不多,如有不懂,请在评论中给出. 效果: ASPX File: <htm

dropzonejs中文翻译手册 DropzoneJS是一个提供文件拖拽上传并且提供图片预览的开源类库.

http://wxb.github.io/dropzonejs.com.zh-CN/dropzonezh-CN/ 由于项目需要,完成一个web的图片拖拽上传,也就顺便学习和了解了一下前端的比较新的技术:HTML5的api,作为一名前端的菜鸟,没什么可说的,直接分享自己学习的资料: 关于HTML5 的这些新的特性大家可以到Mozilla的开发者社区MDN https://developer.mozilla.org/zh-CN/ 上查HTML5的资料 还有就是发掘到的比较牛逼的一篇博客:http:/

原生API实现拖拽上传文件实践

功能: 拖拽上传文件.图片,上传的进度条,能够同时上传多个文件. 完整的demo地址:https://github.com/qcer/FE-Components/tree/master/QDrag 涉及到的API: 1.HTML5的拖拽事件:dragenter,dragover,drop等 2.XMLHttpRequest  Level2 3.FormData 4.(扩展:HTML5的File API) 概述: 1.利用拖拽实践的API将一个普通的div自定义成一个放置目标,这里有一个技巧是放置

基于AngularJS的拖拽上传

随着HTML5的普及,现在大部分浏览器都支持拖拽功能,今天我们要说的就是实现一套拖拽上传的功能(Angularjs+nodejs). 一.首先前端这款插件是基于AngularJS的,下面我们来看主要代码. 引入js: <script src="js/angular.1.3.15.min.js"></script> <script src="js/ng-file-upload-shim.min.js"></script>

jQuery插件之路(三)——文件上传(支持拖拽上传)

好了,这次咱一改往日的作风,就不多说废话了,哈哈.先贴上源代码地址,点击获取.然后直接进入主题啦,当然,如果你觉得我有哪里写的不对或者欠妥的地方,欢迎留言指出.在附上一些代码之前,我们还是先来了解下,上传文件的时候需要利用的一些必要的知识. 首先我们要说的就是FileReader对象,这是一个HTML5提出的,专门用来异步的读取用户计算机上文件的对象,这里有详细的介绍.所以如果我们想要使用它,那么首先我们得先创建一个FileReader对象. var fr = new FileReader()

File杂谈——拖拽上传前传

在<[File杂谈--初识file控件](http://www.seejs.com/archives/668 "File杂谈--初识file控件")>一文中,我们已经对file控件有了初步的了解,并且对制作一个视觉和体验一致的file控件做了较为详细的说明,今天我们继续了解file控件的更多特性,并延伸出更多. ## 新增属性 在HTML5到来之前,绝大多数情况下使用file控件,我们前端工程师需要的有用信息都只能通过value属性获得的文件名字符串来获取(比如:文件类型.

拖拽上传功能

拖拽上传功能旨在实现拖拽文件或者图片上传到你想要保存到的地方.此处上传的是xml文件,可以在里面对文件类型进行限制: 声明:现在的ie浏览器9及以下的版本并不支持该方法实现拖拽上传,如果有大神可以分享ie9及以下的拖拽上传方法将不胜感激: 代码: <body><div id="div">    <h1 align="center">拖拽上传</h1>    <form   id="form1"

Java实现拖拽上传

原文:http://www.open-open.com/code/view/1437358795584 在项目开发中由于实际需求,需要开发拖拽上传的功能,ok! 先看效果图: jsp上传前端代码: <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html>