AngularJs之angular-file-upload上傳組件使用和總結

最近做項目把組件分離,之前用上了第三方組件,裏面的邏輯寫的不是很好,抽空時候研究了下這個組件,然後把它獨立的分離出來了,雖然它是個第三方組件,但是還是有些項目中有些需求它還是實現不了,所以修改了並把它封裝成了一個自己能用的組件。

一.初步認識angular-file-upload

Angular File Upload是AngularJS框架的模塊。支持拖放式上傳,上傳進度,驗證過濾器和文件上傳隊列。它支持本機HTML5上傳,但對於較舊的瀏覽器,其降級爲舊的iframe上傳方法。可與支持標準HTML表單上傳的任何服務器端平臺一起使用。

二.angular-file-upload 基本API

上傳的方式據我所知只有這幾種:

  1. nv-file-select ,input file這種上傳方式 ------ < input type=“file” class=‘pdf-btn’ uploader="$ctrl.fileUploader" nv-file-select>
  2. nv-file-drop,這個可以是任何元素,以拖拽的方式拖到這個元素的區域------ < div class=‘pdf-btn’ nv-file-drop uploader="$ctrl.fileUploader">
  3. nv-file-over,目前我還不知道這個是什麼方式,測試無效果(有知道的同學請指教!)

uploader="$ctrl.fileUploader" 需要注意的是 $ctrl.fileUploader必須是個實例,很顯然我是綁在controller上的

 var  fileUploader = ctrl.fileUploader = new FileUploader({
             //裏面寫的是屬性信息
  });

具體有哪些屬性:
1.url {String}: 上傳文件的服務器路徑。
2.alias {String}: 包含文件的名稱,默認是file。
3.queue {Array}: 上傳隊列。
4.progress {Number}: 上傳隊列的進度,只讀。
5.headers {Object}: 上傳的頭文件信息, 瀏覽器需支持HTML5。
6.formData {Array}: 與文件一起發送的表單數據。
7.filters {Array}: 在文件加入上傳隊列之前應用過濾器.,如果過濾器返回true則文件加入隊列中。
8.autoUpload {Boolean}: 文件加入隊列之後自動上傳,默認是false。
9.method {String}: 請求方式,默認是POST,瀏覽器需支持HTML5。
10.removeAfterUpload {Boolean}: 文件上傳成功之後從隊列移除,默認是false。
11.isHTML5 {Boolean}: 如果瀏覽器支持HTML5上傳則返回true,只讀。
12.isUploading {Boolean}: 文件正在上傳中返回true,只讀。
13.queueLimit {Number} : 最大上傳文件數量(預定義)。
14.withCredentials {Boolean} : 使用CORS,默認是false, 瀏覽器需支持HTML5。
一般 比較常用的 url,autoUpload,queueLimit(目前測試好像沒用),只讀的屬性是改不了的。

var fileUploader = ctrl.fileUploader = new FileUploader({
	//上傳文件的服務器路徑
     url: 'http://localhost:8008/file/file/upload',
    //文件加入隊列之後自動上傳,外面配置它是否讓它自動上傳
     autoUpload: !!ctrl.uploadConfig.autoUpload,
     queueLimit:10
 });

下面說下這個實例對象有哪些方法:
1.addToQueue function(files,options,filters) {:將項目添加到隊列中,其中files一個{FileList|File|HTMLInputElement},options是{Object}和filters是{String}。
2.removeFromQueue function(value) {}:從隊列中移除項目,value是{FileItem}或項的索引。
3.clearQueue function() {}:從隊列中刪除所有元素。
4.uploadItem function(value) {}:上傳的項目,其中,value是{FileItem}或項的索引。
5.cancelItem function(value) {}:取消項目,其中的上傳value是{FileItem}或項目的索引。
6.uploadAll function() {}:上傳隊列中所有待處理的項目。
7.cancelAll function() {}:取消所有當前上傳。
8.destroy function() {}:銷燬一個上傳器。
9.isFile function(value) {return {Boolean};}:如果值是{File},則返回true。
10.isFileLikeObject function(value) {return {Boolean};}:如果值是{FileLikeObject},則返回true 。
11.getIndexOfItem function({FileItem}) {return {Number};}:返回{FileItem}隊列元素的索引。
12.getReadyItems function() {return {Array.};}:返回已準備好上傳項。
13.getNotUploadedItems function() {return {Array.};}:返回隊列中所有未上傳項。
一般比較常用的方法 removeFromQueue,clearQueue,uploadAll,cancelAll。

再說說這個實例對象有哪些回調函數(還是以代碼的形式寫清楚點):

//添加單個文件失敗時觸發
   uploader.onWhenAddingFileFailed = function(item /*{File|FileLikeObject}*/, filter, options) {
       console.info('onWhenAddingFileFailed', item, filter, options);
   };
   //將單個文件添加到隊列時觸發
   uploader.onAfterAddingFile = function(fileItem) {
       console.info('onAfterAddingFile', fileItem);
   };
   //將所有拖動或選定的文件添加到隊列時觸發
   uploader.onAfterAddingAll = function(addedFileItems) {
       console.info('onAfterAddingAll', addedFileItems);
   };
   //在上傳文件之前時觸發
   uploader.onBeforeUploadItem = function(item) {
       console.info('onBeforeUploadItem', item);
   };
   //單個文件上傳進度
   uploader.onProgressItem = function(fileItem, progress) {
       console.info('onProgressItem', fileItem, progress);
   };
   //總文件上傳進度
   uploader.onProgressAll = function(progress) {
       console.info('onProgressAll', progress);
   };
   //單個文件上傳成功時觸發
   uploader.onSuccessItem = function(fileItem, response, status, headers) {
       console.info('onSuccessItem', fileItem, response, status, headers);
   };
   //單個文件上傳失敗時觸發
   uploader.onErrorItem = function(fileItem, response, status, headers) {
       console.info('onErrorItem', fileItem, response, status, headers);
   };
   //單個文件取消上傳時觸發
   uploader.onCancelItem = function(fileItem, response, status, headers) {
       console.info('onCancelItem', fileItem, response, status, headers);
   };
   //單個文件上傳完成時觸發
   uploader.onCompleteItem = function(fileItem, response, status, headers) {
       console.info('onCompleteItem', fileItem, response, status, headers);
   };
   //所有文件上傳完成時觸發
   uploader.onCompleteAll = function() {
       console.info('onCompleteAll');
   };

註釋已經寫的很清楚,方法都比較通俗易懂。好了說完了實例對象,下面說下單個文件的比較常用的屬性,方法和回調。

屬性:
1.index- {Number}序列號上傳。只讀。
2.progress {Number}:文件上傳進度百分比。只讀。
3isReady- {Boolean}文件已準備好上穿。只讀。
4.isUploading {Boolean}:true是否正在上傳文件。只讀。
5.isUploaded {Boolean}:true如果文件已上傳。只讀。
6.isSuccess {Boolean}:true如果文件成功上傳。只讀。
7。isCancel {Boolean}:true如果上傳被取消。只讀。
8.ISERROR {Boolean} - true如果發生錯誤,而文件上傳。只讀。
9.uploader {Object}:Uploader對該文件的父對象的引用。只讀。

方法:
1.remove function() {}:從隊列中刪除此文件
2.upload function() {}:上傳此文件
3.cancel function() {}:取消上傳該文件

回調:
1.onBeforeUpload function() {:在上傳項目之前觸發。
2.onProgress function(progress) {:文件上傳進度。
3.onSuccess function(response, status, headers) {:成功上傳文件
4.onError function(response, status, headers) {:上傳錯誤
5.onCancel- function(response, status, headers) {取消上傳時
6.onComplete function(response, status, headers) {:文件上傳完成(與操作是否成功無關)

可能看到又是這麼多屬性和方法是不是有點懵逼了?其實很簡單,之前實例對象fileUploader是操作總的,下面操作單個文件的,
我們上傳文件不是有很多個文件嗎?那麼這些文件肯定是放到一個數組裏面,[FileItem,FileItem,FileItem,FileItem,FileItem…],可以通過實例對象的queue屬性獲取到$ctrl.fileUploader.queue,一般我們什麼時候會需要操作單個文件呢?一般主要再控制進度條的時候才用的到,看下面代碼:

<ul class="progress-text" ng-repeat="item in $ctrl.fileUploader.queue" ng-show='$ctrl.fileUploader.isUploading'>
    <li>{{ item.file.name }}({{ item.file.size+"KB"}})- <span ng-show='item.progress!==0  && 100 > item.progress'>{{ item.progress + '%'}} </span><span
            ng-show='item.progress===100'>Complete</span><span class="close" ng-click="item.cancel()">X</span></li>
</ul>

上傳中效果如下(自己寫的demo,樣式很隨意,不要在意樣式,主要看效果):
在這裏插入圖片描述
上傳完的效果如下:
在這裏插入圖片描述
好了,基本的API都已經說完了,也應該有個大概的瞭解了!下面我具體說下我的組件是怎麼分離的,首先上傳組件必須是有一個上傳,一個進度條,我們可能不分開他們(因爲它們本來就是一起的),爲了讓進度條擺脫上傳組件束縛最好是分開它們。

三.分析和拆分思路
1.上傳

關於上傳我們必須要考慮以下幾點
1.上傳前,我們要文件約束配置(方便我對組件的控制)
2.上傳驗證(驗證環節,必須要有的,上傳前的驗證或者上傳後的驗證)
3.上傳後,如果有驗證失敗給出錯誤提示。成功後拿到成功的數據
下面我們圍繞這幾點來封裝它,首先看看配置信息:

 ctrl.uploadConfig = {
           //是否允許多選
           "allowMultiple": true,
           //上傳文件是否可以重複
           "allowRepeat": true,
           //自動上傳文件
           "autoUpload": true,
           //成功拿到數據後的事件名,通過派發事件外面可以拿到值
           'dataEvent': 'parentNavItemLoaded',
           //文件上傳最大數量
           "fileSum": 4,
           //文件約束配置
           "fileConstraint": {
               "fromat": ".pdf",
               "fileMaxSize": "4",
               "width": "164",
               "height": "252",
               "fileNameConstraint": {
                   "clazz": "number",
                   "maximum": "4",
                   "minimum": "1"
               }
           }
       };

這個就是這個上傳組件配置信息,基本滿足項目的需求,再看看驗證:

fileUploader.filters.push({
name: "fileUploading",
fn: function (file) {
//文件格式判斷 && 文件大小判斷 && 文件名稱範圍判斷 
return uploadVerify.fileFormat(file, ctrl.uploadConfig.fileConstraint) && uploadVerify.fileSizeRange(file, ctrl.uploadConfig.fileConstraint) && uploadVerify.fileNameRange(file, ctrl.uploadConfig.fileConstraint.fileNameConstraint) && uploadVerify.fileQuantity(this,ctrl.uploadConfig.fileSum);
    }
});
var uploadVerify = {
/** 上傳之後驗證
  * @param {Object} file 上傳文件信息
  * @return Boolean 判斷結果
  * @description 判斷文件上傳總數是否超過
  * -1爲不限制
  */
 "fileQuantity": function (fileUploader,constraint) {
     //檢測上傳最大數量約束有沒有,沒有的話不驗證直接通過,有的話就驗證
     //上傳的數量和約束對比驗證
 	 var  validateResult = constraint? fileUploader.queue.length <=constraint : true;
    return validateResult  || verifyFailed(file, "fileQuantity")
 }

/**
 * @param {Object} file 上傳文件對象
 * @param {String} failedInfo 上傳文件錯誤信息
 * @description 添加失敗信息到失敗文件列表中
 */
function verifyFailed(file, failedInfo) {
    var failureFileList = [];
    var failedInfoMap = {
        "fileQuantity": "上傳失敗,文件上傳數量已經超過" + ctrl.uploadConfig.fileSum,
    };
    failureFileList.push({
        'message': (file.name || file.originalFileName) + failedInfoMap[failedInfo],
    });
};

驗證是每個文件都會驗證的,所以可以根據自己的項目需求來寫,uploadVerify我定義的一個對象,裏面都是驗證的方法, queueLimit:10表示上傳的數量不能超過10,但是沒有提示,所以我這裏自己寫了個fileQuantity驗證,驗證不通過的話會跑verifyFailed方法,得到具體的錯誤信息,然後我在所有文件加到隊裏裏面去驗證它,如果上傳隊列的文件大於約束,就把上傳隊列的多餘的刪除, 因爲之前想在所有文件加入隊裏面拿到上傳的總數再個約束作比較,然後從上傳隊列裏面刪除大於約束的多餘的元素,後來感覺太複雜了,因爲要遍歷,又要去刪除fileUploader.removeFromQueue(file);,太耗性能,所以還是在上面那裏驗證更合適,雖然每個上傳文件都要驗證一次,但是這裏只需要判斷一下數量即可,不怎麼耗性能, 最後這裏會派發個進度條事件(讓進度條組件可以那到這個實例對象fileUploader),讓進度條組件獨立出來。

/**
* @param {Object} addedFileItems 所有成功上傳到上傳列表的文件對象
* @description 多個需上傳文件,添加到上傳隊列中觸發
*/
fileUploader.onAfterAddingAll = function (addedFileItems) {
   //這裏上傳數量和約束進行驗證
   //uploadVerify.fileQuantity(addedFileItems, ctrl.uploadConfig.fileSum, fileUploader);
   //派發進度條事件
   eventBusService.dispatch("progressEvent", ctrl.fileUploader);
};

最後上傳成功後發數據傳到外面去:

/**
 * @description 上傳隊列中,所有文件上傳到服務器完成觸發提
 */
fileUploader.onCompleteAll = function () {
    //上傳完成將所有上傳成功文件通過事件派發
    eventBusService.dispatch(ctrl.uploadConfig.dataEvent, successFileList);
};
2.進度條

每次上傳時候都會派發事件給進度條,所以進度條組件可以取到這個上傳組件的進度

exports.progressBar = {
    templateUrl: "../../uploadH5Builder/progressBar/progressBar.template.html",
    controller: ['eventBusService',
        function progressBar(eventBusService) {
            var ctrl = this;
            ctrl.$onInit = function () {
       			//接受進度條事件動態獲取進度條的值
                eventBusService.addEventListener("progressEvent", function (event) {
                    ctrl.fileUploader = event.target;
                });
            };
        }
    ]
}

這樣的話,我們上傳組件就和進度條組件各自獨立了

<file-uploading upload-config="ctrl.uploadConfig"></file-uploading>
<progress-bar class="progress-bar-element"></progress-bar>

這篇文件主要講我做這個項目的思路,細節部分沒有仔細講,如果有更好的方法可以分享出來,有不正的地方請指正!!好了說到這裏都已經說的差不多了,歡樂的時光總是過得特別快,又到時候和大家講拜拜!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章