欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Nodejs+express+html5 實(shí)現(xiàn)拖拽上傳

 更新時(shí)間:2014年08月08日 18:03:10   投稿:hebedich  
文件上傳是一個(gè)比較常見的功能,傳統(tǒng)的選擇方式的上傳比較麻煩,需要先點(diǎn)擊上傳按鈕,然后再找到文件的路徑,然后上傳。給用戶體驗(yàn)帶來很大問題。html5開始支持拖拽上傳的需要的api。nodejs也是一個(gè)最近越來越流行的技術(shù),這也是自己第一次接觸nodejs。

一、前言

文件上傳是一個(gè)比較常見的功能,傳統(tǒng)的選擇方式的上傳比較麻煩,需要先點(diǎn)擊上傳按鈕,然后再找到文件的路徑,然后上傳。給用戶體驗(yàn)帶來很大問題。html5開始支持拖拽上傳的需要的api。nodejs也是一個(gè)最近越來越流行的技術(shù),這也是自己第一次接觸nodejs,在nodejs開發(fā)中,最常用的開發(fā)框架之一是expess,它是一個(gè)類似mvc模式的框架。結(jié)合html5、nodejs express實(shí)現(xiàn)了拖拽上傳的功能。

二、基礎(chǔ)知識普及

1、NodeJs基礎(chǔ)知識

nodejs簡單來說就是一個(gè)可以讓js在服務(wù)端也能運(yùn)行的開發(fā)平臺,nodejs發(fā)展非常很快,很多國內(nèi)公司也已經(jīng)開始使用比如淘寶等。傳統(tǒng)的web應(yīng)用程序開發(fā)平臺依靠多線程來實(shí)現(xiàn)高并發(fā)請求的響應(yīng)。而nodejs采用了單線程、異步式IO、事件驅(qū)動(dòng)的設(shè)計(jì)模型,給nodejs帶來了巨大的性能提升。這也是nodejs最大的特點(diǎn),在nodejs中,所有的IO操作都是通過回調(diào)的方式進(jìn)行,nodejs在執(zhí)行IO操作時(shí)會把IO請求推送一個(gè)事件隊(duì)列,等待程序進(jìn)行處理,等處理完IO,然后調(diào)用回調(diào)函數(shù)返回結(jié)果。

比如在查詢數(shù)據(jù)庫操作如下:  

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

在以上代碼中,nodejs在執(zhí)行以上語句時(shí),不會等待數(shù)據(jù)庫返回結(jié)果,而是繼續(xù)執(zhí)行后面的語句。在數(shù)據(jù)庫獲取到數(shù)據(jù)后,會發(fā)送到事件循環(huán)隊(duì)列中,等到線程進(jìn)入事件循環(huán)隊(duì)列后,才執(zhí)行callback的東西。

關(guān)于nodejs更多的知識,我也知識看了兩天,了解不多。了解更多的知識可以在網(wǎng)絡(luò)上搜索。

nodejs入門的知識  http://www.nodebeginner.org/index-zh-cn.html    http://www.dbjr.com.cn/article/48755.htm

2、express基礎(chǔ)知識

     nodejs是一個(gè)比較活躍的開源社區(qū),它擁有大量的第三方開發(fā)庫,其中Express是其中最廣泛的、最常用的框架之一。也是nodejs官方推薦的框架。它除了對常見http操作的封裝,還實(shí)現(xiàn)了路由控制、模版解析支持、動(dòng)態(tài)試圖、用戶回話等等。但它也不是一個(gè)萬能的框架,絕大多數(shù)功能是對http的封裝,它只是一個(gè)輕量級的框架。很多功能還需要集成第三方庫還實(shí)現(xiàn)。

     exress提供了非常方便的上傳功能的支持,在文件上傳請求以后,express會接收文件并把文件存在一個(gè)臨時(shí)目錄,然后在路由到的方法中,我們只需把文件從臨時(shí)目錄下拷貝到我們要存放用戶上傳文件夾即可。在文件上傳部分,服務(wù)器端的實(shí)現(xiàn)就是基于express這個(gè)功能來實(shí)現(xiàn)的。

3、html5拖曳上傳api

    html5提供很多新的特性,拖拽事件以及文件上傳就是新特性之一。由于篇幅有限,后面重點(diǎn)介紹拖曳上傳的代碼實(shí)現(xiàn)。就不一一列出html5提供的拖曳上傳的apil了,感興趣的可以參考: http://w3school.com.cn/html5/html5_ref_eventattributes.asp#Mouse_Events       http://www.dbjr.com.cn/html5/85977.html

三、拖曳上傳實(shí)現(xiàn)

1、代碼實(shí)現(xiàn)

先來看下前端js的文件目錄:

其中:

uploader.js主要實(shí)現(xiàn)對html5支持的上傳功能的封裝。

uploaderQueue.js主要實(shí)現(xiàn)上傳文件隊(duì)列的管理,以及文件上傳對象,把文件隊(duì)列中的文件上傳到服務(wù)器。

uploaderApp.js主要文件上傳的入口,主要實(shí)現(xiàn)上傳窗口對拖曳事件的監(jiān)聽并把拖曳文件推進(jìn)上傳文件隊(duì)列,啟動(dòng)文件上傳程序。

下面對核心代碼(需要)做簡單的解釋,全都代碼可以到這里下載: FileUploader

首先對html5提供的文件上傳做簡單的封裝uploader.js

function uploader(url, data, files) {
  this._files = files;
  this._data = data;
  this._url = url;

  this._xhr = null;

  this.onloadstart = {};
  this.onload = {};
  this.onloadend = {};
  this.onprogress = {};
  this.onerror = {};
  this.ontimeout = {};
  this.callback = {};//請求完成后回調(diào)
  _self = this;
 }

 uploader.prototype = {
  init: function () {
   if (!isValid()) {
    throw e;
   }
   this._xhr = new XMLHttpRequest();
   this._bindEvents();
  },
  send: function () {
   if (this._xhr == null) {
    this.init();
   }
   var formData = this._createFormData();
   this._xhr.open('post', this._url, true);
   this._xhr.send(formData);
  },
  _bindEvents: function () {
   _self = this;
   this._xhr.upload.loadstart = function (e) {
    evalFunction(_self.onloadstart, e);
   }
   this._xhr.upload.onload = function (e) {
    evalFunction(_self.onload, e);
   };
   this._xhr.upload.onloadend = function (e) {
    evalFunction(_self.onloadend, e);
   }
   this._xhr.upload.onprogress = function (e) {
    evalFunction(_self.onprogress, e)
   };
   this._xhr.upload.onerror = function (e) {
    evalFunction(_self.onerror, e);
   };
   this._xhr.upload.ontimeout = function (e) {
    evalFunction(_self.ontimeout, e);
   }

   this._xhr.onreadystatechange = function () {
    if (_self._xhr.readyState == 4) {
     if (typeof _self.callback === 'function') {
      var status = _self._xhr.status;
      var data = _self._xhr.responseText;
      _self.callback(status, data);
     }
    }
   }
  },
  _createFormData: function () {
   var formData = new FormData();
   this._addDataToFormData(formData);
   this._addFileToFormData(formData);
   return formData;
  },
  _addDataToFormData: function (formData) {
   if (this._data) {
    for (var item in this._data) {
     formData.append(item, this._data[item]);
    }
   }
  },
  _addFileToFormData: function (formData) {
   if (this._files) {
    for (var i = 0; i < this._files.length; i++) {
     var file = this._files[i];
     formData.append('file[' + i + ']', this._files[i]);
    }
   }
  }
 };
View Code
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進(jìn)行簡單的封裝。uploaderFactory提供一個(gè)簡單的接口,使用它可以像jquery的ajax方法一樣完成,文件上傳調(diào)用。html5中提供的文件上傳的支持,是在原來XMLHttpRequest基礎(chǔ)之上擴(kuò)展一些屬性和方法,提供了FormData對象,來支持文件上傳操作。

文件上傳隊(duì)列(uploaderQueue.js)也是一個(gè)比較重要的對象,它包括兩個(gè)對象一個(gè)是Queue,文件隊(duì)列對象,主要負(fù)責(zé)管理文件隊(duì)列的增刪改查詢等操作,另一個(gè)對象是UploadEngine,文件上傳引擎,它的功能主要是負(fù)責(zé)從文件隊(duì)列中取出文件對象,調(diào)用uploader對象上傳文件,然后更新文件隊(duì)列中的文件狀態(tài)。Queue以及UploadEngine都是單例對象。

首先來看下文件隊(duì)列對象:

(function (upladerQueue) {

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

 var _self = null;

 var instance = null;

 function Queue() {
  this._datas = [];
  this._curSize = 0;//當(dāng)前長度


  _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);

上傳文件隊(duì)列使用一個(gè)數(shù)組管理每個(gè)文件對象信息,每個(gè)文件對象有key,data,status三個(gè)屬性,該對象主要負(fù)責(zé)文件對象的增加、刪除、更新、查找的功能。

上傳文件隊(duì)列中另一個(gè)比較重要的對象是上傳引擎對象(uploadEngine.js)

(function (upladerQueue) {

 var instance = null;
 var _self;

 function uploadEngine() {
  this._url = null;
  this._curUploadingKey = -1;//標(biāo)志
  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);

該對象比較簡單主要提供一個(gè)run以及setUrl方法,用于啟動(dòng)上傳引擎,以及設(shè)置上傳路徑的功能。內(nèi)部使用遞歸的方法把文件隊(duì)列中的方法全部上傳到服務(wù)端。使用uploadItemProgress通知外部上傳的進(jìn)度,使用uploadStatusChanged通知文件上傳狀態(tài),以便更新UI.

uploaderApp.js中主要包括三個(gè)對象,一個(gè)是類似jquery的一個(gè)簡單的jquery對象(App$)。主要用于綁定事件。一個(gè)是uploaderArea對象,是拖曳上傳的窗口區(qū)域,另一個(gè)是入口對象uploaderMain對象。主要用于初始化對象,對外部提供一個(gè)init方法,來初始化整個(gè)對象。

了解關(guān)于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對象,相當(dāng)于各個(gè)對象之間的中介,主要就是做對象的初始化功能、以及對象之間相互調(diào)用。使各個(gè)對象之間相互協(xié)作完成整個(gè)模塊的功能。對外提供一個(gè)init方法來初始化整個(gè)程序,在html頁面中只需如下代碼:

<script type="text/javascript">
  var main=new uploaderApp.main('container');
  main.init();
</script>

以上代碼就是創(chuàng)建一個(gè)入口對象,然后使用init方法來啟動(dòng)整個(gè)程序。

以上是對前端js的主要方法做的簡單解釋,如果想詳細(xì)了解請下載源代碼。下面簡單看下后端js(nodejs)端實(shí)現(xiàn)的主要代碼。

在express基礎(chǔ)知識時(shí),已經(jīng)講過在express已經(jīng)對文件上傳功能做了完整的封裝,當(dāng)路由到action時(shí),文件已經(jīng)完成上傳只是文件上傳到了一個(gè)臨時(shí)目錄,這個(gè)臨時(shí)目錄我們可以在app.js中配置的,配置方式如下:

app.use(express.bodyParser({
  uploadDir:__dirname+'/public/temp'
}));

這樣在文件上傳后文件就存放在/public/temp目錄下,文件名也是express通過一定的算法隨機(jī)獲取的。在我們寫的action中只需要把存在臨時(shí)目錄中的文件移動(dòng)到服務(wù)端存放文件的目錄下,然后刪除臨時(shí)目錄下的文件即可。具體代碼如下:

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、實(shí)現(xiàn)效果

四、獲取代碼

 代碼下載地址:http://www.dbjr.com.cn/jiaoben/202117.html

相關(guān)文章

  • nodejs中art-template模板語法的引入及沖突解決方案

    nodejs中art-template模板語法的引入及沖突解決方案

    本篇文章主要介紹了nodejs中art-template模板語法的引入及沖突解決方案,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-11-11
  • Node.js利用js-xlsx處理Excel文件的方法詳解

    Node.js利用js-xlsx處理Excel文件的方法詳解

    這篇文章主要給大家介紹了關(guān)于Node.js利用js-xlsx處理Excel文件的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。
    2017-07-07
  • express的中間件basicAuth詳解

    express的中間件basicAuth詳解

    這篇文章主要介紹了node.js中express的中間件basicAuth的使用方法,需要的朋友可以參考下
    2014-12-12
  • Node.js如何快速導(dǎo)出多表頭的excel文件實(shí)現(xiàn)方法

    Node.js如何快速導(dǎo)出多表頭的excel文件實(shí)現(xiàn)方法

    這篇文章主要為大家介紹了Node.js如何快速導(dǎo)出多表頭的excel文件實(shí)現(xiàn)方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • npm?install?404問題解決方案

    npm?install?404問題解決方案

    這篇文章主要給大家介紹了關(guān)于npm?install?404問題解決的相關(guān)資料,npm install命令既可以下載服務(wù)器上的模塊,也可以在本地創(chuàng)建自己的模塊,需要的朋友可以參考下
    2023-08-08
  • 如何降低node版本,怎樣實(shí)現(xiàn)降低node版本

    如何降低node版本,怎樣實(shí)現(xiàn)降低node版本

    這篇文章主要介紹了如何降低node版本,怎樣降低node版本問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • node.js通過Sequelize 連接MySQL的方法

    node.js通過Sequelize 連接MySQL的方法

    這篇文章主要介紹了node.js通過Sequelize 連接MySQL的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • Node錯(cuò)誤處理筆記之挖坑系列教程

    Node錯(cuò)誤處理筆記之挖坑系列教程

    因?yàn)閚odejs是單線程的,所以一旦發(fā)生錯(cuò)誤或異常,如果沒有及時(shí)被處理整個(gè)系統(tǒng)就會崩潰。下面這篇文章主要給大家介紹了關(guān)于Node錯(cuò)誤處理筆記之挖坑系列的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧
    2018-06-06
  • 詳解Node.js?應(yīng)用高?CPU?占用率分析方法

    詳解Node.js?應(yīng)用高?CPU?占用率分析方法

    這篇文章主要為大家介紹了Node.js?應(yīng)用高?CPU?占用率分析方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • 淺談如何通過node.js對數(shù)據(jù)進(jìn)行MD5加密

    淺談如何通過node.js對數(shù)據(jù)進(jìn)行MD5加密

    本篇文章將主要針對于在NODE.JS中如何對數(shù)據(jù)進(jìn)行MD5加密,MD5是一種常用的哈希算法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-05-05

最新評論