最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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ā)平臺(tái),nodejs發(fā)展非常很快,很多國內(nèi)公司也已經(jīng)開始使用比如淘寶等。傳統(tǒng)的web應(yīng)用程序開發(fā)平臺(tái)依靠多線程來實(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í)會(huì)把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í),不會(huì)等待數(shù)據(jù)庫返回結(jié)果,而是繼續(xù)執(zhí)行后面的語句。在數(shù)據(jù)庫獲取到數(shù)據(jù)后,會(huì)發(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.fzitv.net/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會(huì)接收文件并把文件存在一個(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.fzitv.net/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.fzitv.net/jiaoben/202117.html

相關(guān)文章

  • Node.js16.15.1的一個(gè)報(bào)錯(cuò)以及解決方案分享

    Node.js16.15.1的一個(gè)報(bào)錯(cuò)以及解決方案分享

    這篇文章主要給大家介紹了關(guān)于Node.js16.15.1的一個(gè)報(bào)錯(cuò)以及解決方案的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-12-12
  • 如何刪除所有node_modules和package-lock配置文件

    如何刪除所有node_modules和package-lock配置文件

    這篇文章主要介紹了如何刪除所有node_modules和package-lock配置文件問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • 淺談Node.js輕量級Web框架Express4.x使用指南

    淺談Node.js輕量級Web框架Express4.x使用指南

    本篇文章主要介紹了淺談Node.js輕量級Web框架Express4.x使用指南,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-05-05
  • websocket+node.js實(shí)現(xiàn)實(shí)時(shí)聊天系統(tǒng)問題咨詢

    websocket+node.js實(shí)現(xiàn)實(shí)時(shí)聊天系統(tǒng)問題咨詢

    最近新學(xué)習(xí)websocket,做了一個(gè)實(shí)時(shí)聊天。用Node.js搭建的服務(wù):serevr.js. 兩個(gè)相互通信頁面:client.html 和server.html 但是就是有很多問題,下面通過本文給大家分享下
    2017-05-05
  • NodeJS項(xiàng)目如何打包成可執(zhí)行文件

    NodeJS項(xiàng)目如何打包成可執(zhí)行文件

    這篇文章主要介紹了NodeJS項(xiàng)目如何打包成可執(zhí)行文件問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • 詳解使用nvm安裝node.js

    詳解使用nvm安裝node.js

    本篇文章主要介紹了詳解nvm安裝node.js,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-07-07
  • Node koa服務(wù)器實(shí)現(xiàn)獲取客戶端ip

    Node koa服務(wù)器實(shí)現(xiàn)獲取客戶端ip

    這篇文章主要為大家詳細(xì)介紹了Node koa服務(wù)器實(shí)現(xiàn)獲取客戶端ip的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解下
    2025-02-02
  • Electron如何通過ffi-napi調(diào)用dll導(dǎo)出接口

    Electron如何通過ffi-napi調(diào)用dll導(dǎo)出接口

    文章介紹了如何在Electron項(xiàng)目中使用ffi-napi模塊調(diào)用DLL文件,并詳細(xì)描述了環(huán)境搭建、安裝Electron和ffi-napi、配置Visual Studio和Python環(huán)境、解決常見問題等步驟,感興趣的朋友跟隨小編一起看看吧
    2025-02-02
  • vscode執(zhí)行npm時(shí)的一些錯(cuò)誤以及處理辦法

    vscode執(zhí)行npm時(shí)的一些錯(cuò)誤以及處理辦法

    在前端開發(fā)過程中,npm的使用是少不了的,所以需要知道基本的操作使用,并且了解常見的異常情況處理,下面這篇文章主要給大家介紹了關(guān)于vscode執(zhí)行npm時(shí)的一些錯(cuò)誤以及處理辦法的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • node后端與Vue前端跨域處理方法詳解

    node后端與Vue前端跨域處理方法詳解

    從目前我了解的情況來看,前后端跨域使用的方式有很多種,這里記錄我使用最順手的一種,即在后端使用cors跨域,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08

最新評論

伊金霍洛旗| 东安县| 邯郸市| 遂宁市| 肥东县| 通化县| 沁阳市| 韶山市| 福州市| 长宁区| 宣恩县| 临清市| 出国| 南溪县| 随州市| 乌审旗| 乃东县| 商都县| 瓦房店市| 迭部县| 龙游县| 调兵山市| 滦平县| 黄浦区| 旅游| 峨眉山市| 油尖旺区| 山西省| 拜泉县| 扎兰屯市| 东至县| 阳春市| 迁西县| 图片| 克拉玛依市| 大城县| 彭泽县| 镇巴县| 万安县| 南投市| 安溪县|