[Vue]寫一個簡單的檔案上傳控制元件

林曉lx發表於2022-04-20
這篇將介紹如何寫一個簡單的基於Vue+Element的檔案上傳控制元件。

控制元件將具有

1. 上傳佇列的列表,顯示檔名稱,大小等資訊,可以顯示上傳進度實時重新整理

2. 取消上傳

[Vue]寫一個簡單的檔案上傳控制元件

 使用Element的uploader控制元件,上傳檔案的行為和樣式不用自己全部實現,使程式碼簡化。且有足夠的擴充套件性,檔案傳輸請求的程式碼可以基於axios完全自己重寫。我們只用關心核心程式碼。

搭建專案框架

首先建立一個空白的專案,引入Element控制元件庫,具體的操作和使用Element控制元件庫請看官方文件:

元件 | Element

後端專案框架的搭建,請閱讀:

編寫檔案上傳程式碼

編寫檔案上傳的幫助類,新建ajaxRequire.ts並鍵入以下內容:

import axios, { CancelTokenSource } from 'axios'
//傳送網路請求
export const request = async (url: string, methods, data: any, onProgress?: (e)=>void, cancelToken?: CancelTokenSource) => {   
    let token = null
    let timeout = 3000;
    if (cancelToken) {
        token = cancelToken.token
        timeout = 0;
    }
    const service = axios.create()
    const re = await service.request({
        headers: {'Content-Type': 'multipart/form-data'},
        url: url,
        method: methods,
        data: data,
        cancelToken: token,
        timeout: timeout,
        onUploadProgress: function (progressEvent) { //原生獲取上傳進度的事件
            if (progressEvent.lengthComputable) {
                if (onProgress) {
                    onProgress(progressEvent);
                }
            }
        },
    })
    return re as any;
}

///獲得取消令牌
export const getCancelToken = () => {
    const source = axios.CancelToken.source();
    return source;
}
[Vue]寫一個簡單的檔案上傳控制元件

onUploadProgress回撥函式將在資料傳輸進度變化的時候觸發,攜帶progressEvent 原生獲取上傳進度事件引數,progressEvent.lengthComputable用於判斷是否可以進行進度計算

axios.CancelToken.source()可以獲得一個源,這個源包含一個唯一Id用於標識哪個請求,和一個cancel函式用於取消請求

編寫控制元件

在App.vue中新增核心的控制元件 <el-upload>

接著新增屬性,注意我們將用自己的方法upload替換el-upload中的上傳操作,因此設定action="/",

:http-request="upload",如下:

<el-upload
      ref="upload"
      :limit="10"
      multiple
      action="/"
      :http-request="upload">
</el-upload>
[Vue]寫一個簡單的檔案上傳控制元件

在script中新增上傳Dto:一些業務相關的資料在這裡定義 比如ownerUserId, fileContainerName等,這些資料可以通過表單與檔案資料一併上傳

export class CreateFileDto {
  id: string;
  fileContainerName: string; //資料夾名稱
  parentId: string;          //檔案的父Id
  ownerUserId: number;        //檔案的歸屬使用者Id
  fileName: string;
  mimeType: string;
  fileType: number; //檔案型別 0:資料夾,1:普通檔案
  file: any;        //檔案資料
}
[Vue]寫一個簡單的檔案上傳控制元件

method中新增一些幫助類函式:

methods: {
  successMessage(value = "執行成功") {
      this.$notify({
        title: "成功",
        message: value,
        type: "success",
      });
    },

  errorMessage(value = "執行錯誤") {
      this.$notify.error({
        title: "錯誤",
        message: value,
      });
    },

  FriendlyFileSize(bytes) {
      bytes = parseFloat(bytes);
      if (bytes === 0) return "0B";
      let k = 1024,
        sizes = ["B", "KB", "MB", "GB", "TB"],
        i = Math.floor(Math.log(bytes) / Math.log(k));
      return (bytes / Math.pow(k, i)).toPrecision(3) + sizes[i];
    },
}
[Vue]寫一個簡單的檔案上傳控制元件

編寫提交前置函式,這裡將做驗證和生成cancelToken:

beforeUpload(file) {
      var token = getCancelToken();
      file.cancelToken = token;
      let isLt2M = true;
      if (this.fileSizeLimit < 0) {
        return true;
      }
      isLt2M = file.size / 1024 / 1024 < this.fileSizeLimit;
      if (!isLt2M) {
        this.loading = false;
        this.errorMessage(`"上傳檔案大小不能超過 ${this.fileSizeLimit}}MB!"`);
      }
      return isLt2M;
}
[Vue]寫一個簡單的檔案上傳控制元件

 編寫upload函式,用於組裝請求資料並交給 ajaxRequire 執行上傳任務

  async upload(option) {
      this.loaded = true;
      var model = new CreateFileDto();
      var file = option.file;
      model.fileName = file.name;
      model.fileType = 2;
      model.mimeType = file.type;
      model.ownerUserId = 1;
      model.fileContainerName = "Container1";
      model.file = file;
      var fd = new FormData();

      Enumerable.from(model).forEach((c) => {
        fd.append(c.key, c.value);
      });

      var token = file.cancelToken;
      await request(
        this.uploadUrl,
        "post",
        fd,
        (e) => {
          if (e.total > 0) {
            e.percent = (e.loaded / e.total) * 100;
          }
          option.onProgress(e);
        },
        token
      );
    },
[Vue]寫一個簡單的檔案上傳控制元件

將token將作為取消傳輸的入口交給ajaxRequire ,自己也保留這個物件用於傳送取消命令,相當於“一式兩份”。

新增el-upload各階段函式的訂閱

:before-upload="beforeUpload"
:on-success="handleSuccess"
:on-remove="handleRemove"
:on-error="handleError"

    handleSuccess(response, file, fileList) {
      this.successMessage("上傳成功");
      this.loading = false;
    },

    handleError(e, file, fileList) {
      this.errorMessage(e);
      this.loading = false;
    },

    handleRemove(file, fileList) {
      if (file.raw.cancelToken) {
        file.raw.cancelToken.cancel();
      }
    },
[Vue]寫一個簡單的檔案上傳控制元件

編寫上傳佇列的Html程式碼:

      <el-button ref="uploadButton">上傳</el-button>
      <span slot="file" slot-scope="{ file }">
        <div class="filelist-item">
          <el-row>
            <el-col :span="6" class="file-icon-frame">
              <i class="el-icon-document file-icon"></i>
            </el-col>
            <el-col :span="18">
              <el-row>
                <el-col :span="20">
                  <label class="file-title">
                    {{ file.name }}
                  </label>
                </el-col>
                <el-col :span="4" style="text-align: right">
                  <el-button
                    type="danger"
                    icon="el-icon-minus"
                    size="mini"
                    circle
                    @click="handleRemove(file)"
                  ></el-button>
                </el-col>
                <el-col :span="24">
                  <label class="file-size">
                    {{ FriendlyFileSize(file.size) }}
                  </label>
                </el-col>
                <el-col :span="24">
                  <el-progress
                    :text-inside="true"
                    :stroke-width="26"
                    :percentage="parseInt(file.percentage, 10)"
                    :status="
                      parseInt(file.percentage, 10) == 100 ? 'success' : ''
                    "
                  >
                  </el-progress
                ></el-col>
              </el-row>
            </el-col>
          </el-row>
        </div>
      </span>
[Vue]寫一個簡單的檔案上傳控制元件

執行

進入後端專案的目錄(api),執行:

dotnet run
[Vue]寫一個簡單的檔案上傳控制元件

前端專案目錄(web),執行

yarn serve
[Vue]寫一個簡單的檔案上傳控制元件

執行效果:

 

 [Vue]寫一個簡單的檔案上傳控制元件

 

 

完整程式碼:

file-uploader-sample/web at master · jevonsflash/file-uploader-sample (github.com)

專案地址:

jevonsflash/file-uploader-sample (github.com)

相關文章