1. 程式人生 > >react 中使用 plupload 上傳檔案

react 中使用 plupload 上傳檔案

這幾天做一個專案的迭代開發,需要在react 中使用plupload 外掛實現上傳檔案。需求很簡單,如下圖,點選“...” 按鈕選擇檔案,點選“Import”按鈕上傳檔案。


 plupload 上傳檔案大概分為以下幾步:

1. 新建一個uploader例項,並在構造時配置好上傳的相關屬性。

const uploader = new plupload.Uploader({
     browse_button: 'selectFileId', //指定調起選擇檔案對話方塊的DOM 元素或其ID,注意是DOM元素
     url: ‘put upload file url here’,
     multi_selection: false,
   init: { //在裡面定義各種事件的回撥
        BeforeUpload: (uploader,file) => {
          
        },
        FilesAdded:(uploader,files)=>{
          
        },
        FileUploaded:(uploader,file,info) =>{
          
        }, 
   }
})

2. 初始化例項

this.uploader.init();

3. 在確定匯入的按鈕相關觸發事件(例如onclick)的回撥中呼叫例項的start方法,開始上傳

handleImport = () => {
    this.uploader.start();
}

但是在除錯過程中問題一就出現了。

問題一:發現點選“...” 按鈕無法調起選擇檔案對話方塊。跟蹤發現init()函式也有被呼叫,說明uploader初始化沒成功。反覆檢查配置,沒發現配置有任何問題。既然配置沒問題,那就可能是初始化的時機不對。檢查發現,uploader的例項建立和init初始化都放在了 react component的 componentWillMount() 函式中。 突然醒悟,componentWillMount 是在react 建立的元件插入DOM節點之前觸發的,也就是說呼叫時DOM中還沒有ID為selectFlagId的元素,uploader 初始化時當然是找不到觸發DOM的。謎底解開。。。

問題一解決後,接著測試,又發現了問題二。

問題二:當第一次觸發上傳,服務端檢查發現檔案內容不符合規範,返回錯誤。這個時候,使用者直接開啟檔案修改儲存,再在介面直接點選上傳按鈕,發現無法上傳檔案,但是重新選擇檔案後,又可以上傳。開啟chrome 開發工具,檢查網路請求,發現無上傳請求發出。然後設斷點跟蹤,發現handleImport() 函式是呼叫了的,uploader 的start 函式也是呼叫了的,但是BeforeUpload函式沒有進入。也就是說是uploader 在接受到start訊號後,沒有觸發上傳。此刻小編腦上各種⭕️, 到這裡,就需要去了解pluploader內部的上傳機制了。開啟plupload 官方文件查閱,發現在plupload內部有一個上傳佇列,每次選擇檔案後,都會把檔案放入佇列中,每次start時,都會從佇列中拿任務。但是由於第一上傳已經觸發,任務已經執行;第二次點選時,任務佇列其實是空的,拿不到任務,自然不會上傳;如果再次選擇檔案,檔案又會被放入佇列,因此可以拿到任務,進行上傳。謎底揭曉了。

那問題來了,怎麼解決呢?

首次需求是要滿足的,不能要求使用者一定要再選一次檔案吧,畢竟使用者是我們的衣食父母啊; 

其次,怎麼樣通過介面往佇列里加任務,選擇檔案時呼叫的介面是不是public介面;

最後,檔案物件還有嗎,怎麼獲取。

繼續搜尋官方文件API,發現pluploader有一個addFile(file, [fileName])的介面, 官方解釋如下:

“Adds file to the queue programmatically. Can be native file, instance of Plupload.File, instance of mOxie.File, input[type="file"] element, or array of these. Fires FilesAdded, if any files were added to the queue. Otherwise nothing happens.”  https://www.plupload.com/docs/v2/Uploader#addFile-method-filefileName

大概翻譯下,該介面用於程式內部呼叫增加檔案到佇列中。檔案可以是本地檔案,Plupload.File的例項,mOxie.File 例項,input[type="file"] 元素,或者是這些內容的陣列。如果有檔案增加到佇列中,FilesAdded 事件會被觸發,反之,則不會觸發事件。

好了,介面有了,檔案物件呢? 根據介面描述,介面接受的的檔案物件可選擇多種。但是哪一種是目前可以獲取的呢?首先想到的是Plupload.File的例項,查詢物件uploader物件的屬性,發現有一個files屬性,官方描述為:Current upload queue, an array of File instances.”  

/**
* Current upload queue, an array of File instances.
*
* @property files
* @type Array
* @see plupload.File
*/
files : files,

第一次看到這個描述時,小編認為檔案一旦上傳完,就會從佇列裡移除,那這個files應該是個空陣列啊。但是debug 發現,並非如此。這個files屬性裡會一直儲存增加的File instances,只是用status來標記File的狀態。官方描述:“Status constant matching the plupload states QUEUED, UPLOADING, FAILED, DONE.”

欣喜若狂啊,直接取最後一個File instance,作為addFile 的引數不就可以了。但是,測試結果是No!  追其原因,可能這個File instances 裡面的status導致的,重置status,依然無效,但是意外發現,Plupload.File的例項下面有一個getNative()的方法,官方解釋:“Returns native window.File object, when it's available.” 這不就是我們需要的native file麼,