搜尋
首頁web前端H5教程Nodejs+express+html5 實作拖曳上傳

一、前言

檔案上傳是比較常見的功能,傳統的選擇方式的上傳比較麻煩,需要先點選上傳按鈕,然後再找到檔案的路徑,然後上傳。給用戶體驗帶來很大問題。 html5開始支援拖曳上傳的需要的api。 nodejs也是最近越來越流行的技術,這也是自己第一次接觸nodejs,在nodejs開發中,最常用的開發框架之一是expess,它是一個類似mvc模式的框架。結合html5、nodejs express實現了拖曳上傳的功能。

二、基礎知識普及

1、NodeJs基礎知識

二、基礎知識普及

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更多的知識,我也知識看了兩天,了解不多。了解更多的知識可以在網路上搜尋。

2、express基礎知識

     nodejs是一個比較活躍的開源社區,它擁有大量的第三方開發庫,其中Express是其中最廣泛的、最常用的框架之一。也是nodejs官方推薦的框架。除了對常見http操作的封裝,它也實現了路由控制、模版解析支援、動態試圖、使用者回話等等。但它也不是萬能的框架,絕大多數功能是對http的封裝,它只是一個輕量級的框架。很多功能還需要整合第三方函式庫還實現。

     exress提供了非常方便的上傳功能的支持,在文件上傳請求以後,express會接收文件並把文件存在一個臨時目錄,然後在路由到的方法中,我們只需把文件從臨時目錄下拷貝到我們要存放用戶上傳資料夾即可。在檔案上傳部分,伺服器端的實作就是基於express這個功能來實現的。

3、html5拖曳上傳api

    html5提供許多新的特性,拖曳事件以及檔案上傳就是新功能之一。由於篇幅有限,後面重點介紹拖曳上傳的程式碼實作。就不一一列出html5提供的拖曳上傳的apil了

三、拖曳上傳實作

1、程式碼實作

Nodejs+express+html5 实现拖拽上传先來看下前端js的檔案目錄:

其中:

js主要實作html5支援的上傳功能的封裝。

uploaderQueue.js主要實現上傳檔案佇列的管理,以及檔案上傳對象,把檔案佇列中的檔案上傳到伺服器。

uploaderApp.js主要檔案上傳的入口,主要實現上傳視窗對拖曳事件的監聽並把拖曳檔案推進上傳檔案佇列,啟動檔案上傳程式。

下面對核心程式碼(需要)做簡單的解釋,全都程式碼可以到這裡下載: 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 = {};//请求完成后回调
  _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(&#39;file[&#39; + i + &#39;]&#39;, 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 === &#39;function&#39;) {
     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 === &#39;function&#39;) {
    this.uploadStatusChanged(this._curUploadingKey, upladerQueue.UploadStatus.Uploading);
   }
   upladerQueue.Queue.setItemStatus(this._curUploadingKey, upladerQueue.UploadStatus.Uploading);
  },
  _completedUploadItem: function (status, data) {
   if (typeof this.uploadStatusChanged === &#39;function&#39;) {
    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 = &#39;file/uploader&#39;;
 }
 
 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(&#39;container&#39;);
  main.init();
</script>

以上代码就是创建一个入口对象,然后使用init方法来启动整个程序。

以上是对前端js的主要方法做的简单解释,如果想详细了解请下载源代码。下面简单看下后端js(nodejs)端实现的主要代码。

在express基础知识时,已经讲过在express已经对文件上传功能做了完整的封装,当路由到action时,文件已经完成上传只是文件上传到了一个临时目录,这个临时目录我们可以在app.js中配置的,配置方式如下:

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

这样在文件上传后文件就存放在/public/temp目录下,文件名也是express通过一定的算法随机获取的。在我们写的action中只需要把存在临时目录中的文件移动到服务端存放文件的目录下,然后删除临时目录下的文件即可。具体代码如下:

function uploader(req, res) {
 if (req.files != &#39;undifined&#39;) {
  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: &#39;上传成功&#39;
     };
     res.send(res);
    } else {
     uploadFile(req, res, path, index + 1);
    }
   });
 }
}

2、实现效果

Nodejs+express+html5 实现拖拽上传

更多Nodejs+express+html5 实现拖拽上传相关文章请关注PHP中文网!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
H5代碼示例:實際應用和教程H5代碼示例:實際應用和教程Apr 25, 2025 am 12:10 AM

H5提供了多種新特性和功能,極大地增強了前端開發的能力。 1.多媒體支持:通過和元素嵌入媒體,無需插件。 2.畫布(Canvas):使用元素動態渲染2D圖形和動畫。 3.本地存儲:通過localStorage和sessionStorage實現數據持久化存儲,提升用戶體驗。

H5和HTML5之間的連接:相似性和差異H5和HTML5之間的連接:相似性和差異Apr 24, 2025 am 12:01 AM

H5和HTML5是不同的概念:HTML5是HTML的一個版本,包含新元素和API;H5是基於HTML5的移動應用開發框架。 HTML5通過瀏覽器解析和渲染代碼,H5應用則需要容器運行並通過JavaScript與原生代碼交互。

H5代碼的基礎:密鑰元素及其目的H5代碼的基礎:密鑰元素及其目的Apr 23, 2025 am 12:09 AM

HTML5的關鍵元素包括、、、、、等,用於構建現代網頁。 1.定義頭部內容,2.用於導航鏈接,3.表示獨立文章內容,4.組織頁面內容,5.展示側邊欄內容,6.定義頁腳,這些元素增強了網頁的結構和功能性。

HTML5和H5:了解常見用法HTML5和H5:了解常見用法Apr 22, 2025 am 12:01 AM

HTML5和H5沒有區別,H5是HTML5的簡稱。 1.HTML5是HTML的第五個版本,增強了網頁的多媒體和交互功能。 2.H5常用於指代基於HTML5的移動網頁或應用,適用於各種移動設備。

HTML5:現代網絡的基礎(H5)HTML5:現代網絡的基礎(H5)Apr 21, 2025 am 12:05 AM

HTML5是超文本標記語言的最新版本,由W3C標準化。 HTML5引入了新的語義化標籤、多媒體支持和表單增強,提升了網頁結構、用戶體驗和SEO效果。 HTML5引入了新的語義化標籤,如、、、等,使網頁結構更清晰,SEO效果更好。 HTML5支持多媒體元素和,無需第三方插件,提升了用戶體驗和加載速度。 HTML5增強了表單功能,引入了新的輸入類型如、等,提高了用戶體驗和表單驗證效率。

H5代碼:編寫清潔有效的HTML5H5代碼:編寫清潔有效的HTML5Apr 20, 2025 am 12:06 AM

如何寫出乾淨高效的HTML5代碼?答案是通過語義化標籤、結構化代碼、性能優化和避免常見錯誤。 1.使用語義化標籤如、等,提升代碼可讀性和SEO效果。 2.保持代碼結構化和可讀性,使用適當縮進和註釋。 3.優化性能,通過減少不必要的標籤、使用CDN和壓縮代碼。 4.避免常見錯誤,如標籤未閉合,確保代碼有效性。

H5:如何增強網絡上的用戶體驗H5:如何增強網絡上的用戶體驗Apr 19, 2025 am 12:08 AM

H5通過多媒體支持、離線存儲和性能優化提升網頁用戶體驗。 1)多媒體支持:H5的和元素簡化開發,提升用戶體驗。 2)離線存儲:WebStorage和IndexedDB允許離線使用,提升體驗。 3)性能優化:WebWorkers和元素優化性能,減少帶寬消耗。

解構H5代碼:標籤,元素和屬性解構H5代碼:標籤,元素和屬性Apr 18, 2025 am 12:06 AM

HTML5代碼由標籤、元素和屬性組成:1.標籤定義內容類型,用尖括號包圍,如。 2.元素由開始標籤、內容和結束標籤組成,如內容。 3.屬性在開始標籤中定義鍵值對,增強功能,如。這些是構建網頁結構的基本單位。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具