換個姿勢上傳?el-upload + qiniu-js 的實現

YDJFE發表於2018-03-24

關於element-uiel-upload,實際上issue中提到的次數也不少,很多初試者可能 get 不到愉快使用的點,提了issue之後又大多因為規範問題直接被機器人過濾或者關閉。例如最近一次相關的issue是想尋求關於http-request的使用,但也因為規範問題被直接關閉。所以我們就稍微做一個比較接地氣的業務類分享。

0. 我們要什麼?

這個問題就簡單了:首先,我們需要一個好看的皮囊!那Vue基本沒得選了,element-uiel-upload很符合口味。其次,我們需要一個有趣的靈魂,我們是使用七牛的物件儲存的,但我們的想法是想使用qiniu-js這個官方的SDK。因為el-upload開放了請求方法的自定義,所以我們改造一下。

1. 我們怎麼做?

qiniu-js SDK

直接就看文件了。

實際上為什麼要直接用七牛的 SDK 而不是元件帶的請求方法將就用一下就好呢?這裡我有兩點可以解釋:穩定,懶。七牛放出來的東西肯定更適合他們自己的服務,所以自己安排action啊或者data什麼的可能會安排錯,那還不如直接按照他們給出的方式來做就行了。比如分片,如果只是從使用角度來看,直接用SDK的話我就不用去關心到底要怎麼分,要怎麼上傳,要怎麼結合成一個檔案。我只需要讓後端把上傳策略都做好放出一個token,剩下的就什麼都不用做了。還有瀏覽器方面,既然跟Vue一起使用了,那麼瑣事webpack已經幫我們處理了,我們根本不用關心。

好了關於安裝和引入就跳過了,直接看方法如何呼叫。簡單看它的上傳是以觀察者形式,通過qiniu.upload註冊一個方法,通過該方法進行訂閱即上傳操作,取消訂閱即取消上傳操作。而觀察者又會拆分出三個方法:next, error, complete,簡單說就是管過程,錯誤以及完成情況。這部分可以直接依據文件寫:

const observable = qiniu.upload(file, key, token, putExtra, config)
const subscription = observable.subscribe(next, error, complete) // 上傳開始

// subscription.unsubscribe() 這個方法可以取消操作
複製程式碼

next方法接收一個引數,這個引數包含各種上傳進度資訊:

const next = ({ total }) => {
  // 
  const {
    loaded, // 已上傳大小,單位為位元組。
    total,  // 本次上傳的總量控制資訊,單位為位元組
    percent // 當前上傳進度,範圍:0~100
  } = total
};
複製程式碼

所以如果你沒有什麼特殊需求的話,只需要percent能捕獲進度就行了。

complete接收一個引數,當上傳完整之後,伺服器按照配置給你返回的內容,具體顯示什麼都看自己的後端如何配置。

error顧名思義就是當上傳出現錯誤的時候做出處理,對錯誤的處理也是因人而異,直接看文件就行。

至此先保留,再看el-upload

el-upload

我建議是去瞟一眼el-upload原始碼,這樣也方便理解,當一個檔案拖入或新增到元件的時候,好看的皮囊和有趣的靈魂是如何協調工作的。如果只是想理解上傳的方式,只看有出現ajax的兩個檔案就行:一個是ajax.js還有一個是upload.vue

如果你說:我不想看原始碼!然後又想能跟你寫的請求方法結合,可以!有一個蠢方法:先定義一個方法接收一個引數,這個方法直接向uploadhttp-request進行繫結:

{
  template: `<el-upload :http-request="request" />`
  methods: {
    request(obj) { console.log(obj) }
  }
}
複製程式碼

至此你就能看到el-upload打包的所有請求資訊的了,你就可以根據這個好看的皮囊設計靈魂了。(有一個issue提到關於headerdata的問題,實際上都會包含在這之中)

但我還是建議可以看一下原始碼,因為你看了原始碼之後你就會發現一些細節等下可以用到,比如upload.vue133~143這幾行程式碼:

onProgress: e => {
  this.onProgress(e, rawFile);
},
onSuccess: res => {
  this.onSuccess(res, rawFile);
  delete this.reqs[uid];
},
onError: err => {
  this.onError(err, rawFile);
  delete this.reqs[uid];
}
複製程式碼

而這個時候你就能會知道:噢!我等下可以利用到這個皮囊的進度條顯示,成功以及失敗的處理。並不需要自己再去引入更多的元件或者更多的回撥操作。甚至如果以後不再用“七牛”作為請求方法,元件也可複用不用修改。所以#8291就有點可惜了,如果他還沒找到方法的話希望這篇文章可以幫到他。

3. merge

弄清楚之後,就是把他們“揉起來”。對於el-upload能用的資訊我們已經清楚,剩下的關於業務上的操作就移步element的官方文件即可。我們來製造靈魂,在此之前註釋一下:我們團隊是非常強調規範和擁抱classes + TypeScript這種方式的,但寫這篇文章的人是比較喜歡直接用JavaScript,而且應該更多人需要的是後者所以本次產出的“渣程式碼”用JavaScript,那麼:

// upload.js

// token 找後端,obj 這裡指代從 el-upload 接收到的 object
export const upload = token => obj => {
  const { file } = obj 

  // 關於 key 要怎麼處理自行解決,但如果為 undefined 或者 null 會使用上傳後的 hash 作為 key.
  const key = "" 
  
  // 因人而異,自行解決
  const putExtra = {},
        config   = {} 

  const observable = qiniu.upload(file, key, token, putExtra, config)

  // 剛剛得到的資訊可以使用了,這樣可以使用到 el-upload 的進度條
  const next = ({ total }) => obj.onProgress({ percent: total.percent })

  const error = err => obj.onError(err)

  const complete = res => obj.onSuccess(res)

  const subscription = observable.subscribe(next, error, complete)
  return subscription // 返回以方便取消上傳操作
}
複製程式碼
Vue.component('upload', {
  template: `<el-upload :http-request="request" />`
  methods: {
    request(obj) {
      // 你怎麼搞到token我不管!
      const uploader = upload(token)
      const subscription = uploader(obj) 
    }
  }
})
複製程式碼

這是一個拋磚引玉的操作,大致上就只有這樣了,剩下全靠愛和定製就完事兒了!

相關文章