中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Vue如何實現封裝一個切片上傳組件

發布時間:2023-03-16 14:11:56 來源:億速云 閱讀:112 作者:iii 欄目:開發技術

今天小編給大家分享一下Vue如何實現封裝一個切片上傳組件的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

    組件效果

    單文件切片上傳

    Vue如何實現封裝一個切片上傳組件

    多文件切片上傳

    Vue如何實現封裝一個切片上傳組件

    組件使用案例

    <template>
      <div id="app">
        <div class="upload-wrap">
          <UploadSlice
            :action="uploadInfoSlice.actionChunk"
            :headers="uploadInfoSlice.headers"
            :limit="uploadInfoSlice.limit"
            :accept="uploadInfoSlice.accept"
            :show-file-list="false"
            cancelable
            :on-success="handleSuccess"
            :on-remove="handleRemove"
            :on-cancel="handleCancel"
            :on-upload-pre="handleUploadPre"
            :on-upload-merge="handleUploadMerge"
            :on-form-data="genFormData"
          />
        </div>
      </div>
    </template>
    
    <script>
    import UploadSlice from './components/UploadSlice.vue'
    import { uploadPre, uploadMerge } from '@/api/upload-slice'
    
    export default {
      name: 'App',
      components: {
        UploadSlice
      },
      data() {
        return {
          // 上傳部分
          uploadInfoSlice: {
            actionChunk: process.env.VUE_APP_BASE_API + '/storage/file/v3/chunk', // 切片請求上傳路徑
            headers: { 'Authorization': 'Bearer XXX' }
          }
        }
      },
      methods: {
        // 分片預請求
        async handleUploadPre(file) {
          const form = new FormData()
          form.append('fileSource', 'APPLICATION')
          form.append('originFileName', file.name)
          let res = ''
          try {
            res = await uploadPre(form)
          } catch (error) {
            throw new Error(error)
          }
        },
        // 構造分片參數
        genFormData(chunks, uid) {
          const prepareId = this.getCurrentPrepareId(uid)
          return chunks.map(chunk => {
            const form = new FormData()
            form.append('chunk', chunk.file)
            form.append('uploadId', prepareId)
            form.append('partNumber', chunk.index)
            return form
          })
        },
        // 合并請求
        async handleUploadMerge(file, uid) {
          const prepareId = this.getCurrentPrepareId(uid)
          const form = new FormData()
          form.append('fileSource', 'APPLICATION')
          form.append('hash', prepareId)
          form.append('filename', file.name)
          // return 建議使用, 用于handleSuccess獲取數據
          try {
            const res = await uploadMerge(form)
            return res
          } catch (error) {
            return error
          }
        },
        // 判斷當前處理prepareId
        getCurrentPrepareId(uid) {
          for (const item of this.progressFileList) {
            if (item.uid === uid) {
              return item.prepareId
            }
          }
        }
      }
    }
    </script>

    使用文檔

    Attribute

    標紅色部分為二次封裝處理過的功能,其他為el-upload自帶屬性

    參數說明類型可選值默認值備注
    action必選參數,分片上傳的地址,預請求和合并請求在組件外操作String--
    headers設置上傳的請求頭部String--
    multiple是否支持多選文件boolean-

    accept可上傳文件類型,多種類型用","分隔 (格式不符合自動提示)String--
    on-remove文件列表移除文件時的鉤子function(file, fileList)&mdash;&mdash;
    on-success文件上傳成功時的鉤子function(response, file, fileList)&mdash;&mdash;
    on-error文件上傳失敗時的鉤子function(err, file, fileList)&mdash;&mdash;
    on-progress文件上傳時的鉤子function(event, file, fileList)&mdash;&mdash;
    on-change文件狀態改變時的鉤子,添加文件、上傳成功和上傳失敗時都會被調用function(file, fileList)&mdash;&mdash;
    on-exceed文件超出個數限制時的鉤子function(files, fileList)&mdash;&mdash;
    list-type文件列表的類型stringtext/picture/picture-cardtext
    show-file-list是否顯示已上傳文件列表(文件分片上傳時建議設置false,否則會有兩個進度條)boolean&mdash;true
    file-list上傳的文件列表, 例如: [{name: 'food.jpg', url: 'xxx.cdn.com/xxx.jpg'}]array&mdash;[]
    disabled是否禁用boolean&mdash;false
    cancelable是否支持取消boolean&mdash;false
    limit最多允許上傳個數(超出個數自動提示)number&mdash;&mdash;
    size限制大小String&mdash;&mdash;
    hideBtn是否在上傳過程中隱藏上傳按鈕boolean&mdash;&mdash;false

    Slot

    插槽名說明
    trigger觸發文件選擇框的內容
    tip提示說明文字
    more-tips在默認提示后補充說明

    封裝過程

    切片上傳組件是基于el-upload進行的二次封裝,文章開頭組件效果演示可以看到上傳一個文件會發送三個請求:prepare,chunk, merge,也就是整個上傳過程,主要分為三步:1.預請求 2.分片請求 3.合并請求,預請求和合并請求就是我們正常的http請求,主要處理的是分片請求,分片請求主要的步驟是:

    • 將文件切片

    • 構造切片請求參數

    • 控制分片請求的并發

    1. 文件切片

    el-upload上傳后, 在on-change屬性的回調里可以獲取文件file,通過file.raw.slice對文件進行切片,目前的切片規則是:1.小于10M 固定一片 2.小于50M 文件10%為一片 3.大于50M 固定5M 一片(可以根據自己的需求進行修改)

    genFileChunks(file) {
      const chunks = []
      let cur = 0
      // 小于10M 固定一片
      if (file.size < (10 * 1024 * 1024)) {
        chunks.push({
          index: cur,
          file: file.raw.slice(cur, file.size),
          originFilename: file.name
        })
        return chunks
      }
      // 小于50M 文件10%為一片
      if (file.size < (50 * 1024 * 1024)) {
        const chunkSize = parseInt(file.size * 0.1)
        while (cur < file.size) {
          chunks.push({
            index: cur,
            file: file.raw.slice(cur, cur + chunkSize),
            originFilename: file.name
          })
          cur += chunkSize
        }
        return chunks
      }
      // 大于50M 固定5M 一片
      const chunkSize = parseInt(5 * 1024 * 1024)
      while (cur < file.size) {
        chunks.push({
          index: cur,
          file: file.raw.slice(cur, cur + chunkSize),
          originFilename: file.name
        })
        cur += chunkSize
      }
      return chunks
    },

    一個32M的文件按照10%切一片,構造好的切片數據是這樣的

    Vue如何實現封裝一個切片上傳組件

    2. 構造切片請求參數

    切片請求不同業務的參數是變化的,所以參數部分可以拋出給父組件處理,增加組件的復用性

    父組件

    <template>
      <UploadSlice
        :action="uploadInfoSlice.actionChunk"
        :headers="uploadInfoSlice.headers"
        :on-form-data="genFormData"
      />
    </template>
    
    <script>
      methods: {
        // 構造分片參數
        genFormData(chunks, uid) {
          const prepareId = this.getCurrentPrepareId(uid)
          return chunks.map(chunk => {
            const form = new FormData()
            form.append('chunk', chunk.file)
            form.append('uploadId', prepareId)
            form.append('partNumber', chunk.index)
            return form
          })
        },
      },
    </script>

    子組件

    <template>
      <el-upload
          action=""
          :accept="accept"
      >
    </template>
    
    <script>
      props: {
        onFormData: {
          type: Function,
          default: () => {}
        },
      },
      methods: {
        async uploadChunks(uid) {
          // 預請求
          // ---------------
    
          // 上傳切片
          const requests = this._genRequest(this._genUploadData(uid), uid)
          // 控制并發
          await this.sendRequest(requests)
          
          // 合并請求
          // ---------------
        },
        
        // 構造分片參數
        _genUploadData(uid) {
          const chunks = this.getCurrentChunks(uid)
          return this.onFormData(chunks, uid)
        },
        
        // 生成調用請求:[Promise, Promise]
        _genRequest(uploadData, uid) {
          console.log('uploadData', uploadData)
          const file = this.getCurrentFile(uid)
          const chunks = this.getCurrentChunks(uid)
          return uploadData.map((form, index) => {
            const options = {
              headers: this.$attrs.headers,
              file: file,
              data: form,
              action: this.action,
              onProgress: progress => {
                chunks[index].progress = Number(
                  ((progress.loaded / progress.total) * 100).toFixed(2)
                )
                this.handleProgress(progress, file, uid)
              }
            }
            return options
          })
        },
      },
    </script>

    3. 控制分片請求的并發

    切片上傳如果不控制并發,在分片很多時,就會同時發送很多個http請求,導致線程阻塞,影響頁面其他請求的操作,所以控制并發是需要的。我設置的是最多允許3個并發請求。

        sendRequest(requests, limit = 3) {
          return new Promise((resolve, reject) => {
            const len = requests.length
            let counter = 0
            let isTips = false // 只提示一次失敗
            let isStop = false // 如果一個片段失敗超過三次 認為當前網洛有問題 停止全部上傳
            const startRequest = async() => {
              if (isStop) return
              const task = requests.shift()
              if (task && task.file.status !== 'cancel') {
                // 利用try...catch捕獲錯誤
                try {
                  // 具體的接口  抽離出去了
                  await ajax(task)
                  if (counter === len - 1) { // 最后一個任務
                    resolve()
                  } else { // 否則接著執行
                    counter++
                    startRequest() // 啟動下一個任務
                  }
                } catch (error) {
                  // 網絡異常
                  if (error === 'NETWORK_ERROR' && !isTips) {
                    Message.error('網絡異常,文件上傳失敗')
                    this.upLoading = false
                    this.preLoading = false
                    isTips = true
                    this.handleRemove('', [])
                  }
    
                  // 接口報錯重試,限制為3次
                  if (task.error < 3) {
                    task.error++
                    requests.unshift(task)
                    startRequest()
                  } else {
                    isStop = true
                    reject(error)
                  }
                }
              }
            }
            // 啟動任務
            while (limit > 0) {
              // 模擬不同大小啟動
              setTimeout(() => {
                startRequest()
              }, Math.random() * 2000)
              limit--
            }
          })
        }
      }

    以上就是“Vue如何實現封裝一個切片上傳組件”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    vue
    AI

    聂拉木县| 潍坊市| 南充市| 林口县| 新巴尔虎左旗| 平乐县| 湄潭县| 泾川县| 维西| 湛江市| 白朗县| 阜阳市| 石嘴山市| 巨鹿县| 井陉县| 遂溪县| 司法| 界首市| 抚州市| 永靖县| 霍邱县| 班戈县| 乌苏市| 搜索| 额尔古纳市| 都江堰市| 高邑县| 湟中县| 青海省| 长宁县| 毕节市| 临邑县| 晋中市| 特克斯县| 桐梓县| 灵璧县| 西乌| 仙桃市| 分宜县| 阿巴嘎旗| 米泉市|