Optimierung des Upload-Erlebnisses: Eine perfekte Anleitung zur Verwendung von Vue und Element UI zum separaten Hochladen mehrerer Dateien und zur Anzeige von Fortschrittsbalken

        Ich bin kürzlich auf ein Projekt gestoßen, das das Hochladen von Dateien nutzte und die Möglichkeit erforderte, die hochgeladenen Dateiinformationen hinzuzufügen und zu bearbeiten, die Datei in einen Binärstream zu konvertieren und Parameter an das Backend zu übergeben, und außerdem einen Echtzeit-Fortschrittsbalken benötigte.

        Da gibt es nicht viel zu sagen, kommen wir gleich zu den Renderings

  1. Vorlagencode

<template>
  <div>
    <p class="title">可以选择多文件进行批量上传</p>
    <div>
      <el-upload
        class="upload-demo"
        ref="upload"
        action="#"
        :http-request="uploadReport"
        :headers="{ 'x-auth-token': token }" //必要的条件,请求时的token,根据看自己请求时的toen字段名来决定
        accept=".pdf, .doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.html"//文件类型
        :auto-upload="false"
        :on-change="changeFile"
        :file-list="fileList"
        :show-file-list="false"
        multiple
      >
        <el-button slot="trigger" type="primary">选取文件</el-button>
        <div style="padding: 0 10px">
          <el-table
            :data="fileList"
            border
            :header-cell-style="{ background: '#ddd' }"
          >
            <el-table-column
              prop="name"
              label="文件名"
              align="center"
              show-overflow-tooltip
            >
            </el-table-column>
            <el-table-column prop="size" label="大小" align="center">
            </el-table-column>
            <el-table-column label="进度" align="center">
              <template slot-scope="scope">
                <el-progress
                  :text-inside="true"
                  :stroke-width="24"
                  :percentage="progressArr[scope.$index]"
                  status="success"
                ></el-progress>
              </template>
            </el-table-column>
            <el-table-column prop="status" label="状态" align="center">
              <template slot-scope="scope">
                <span v-if="statusArr[scope.$index] !== '上传成功'" style="color:red">{
   
   {statusArr[scope.$index]}}</span>
                <span
                  v-else-if="
                    scope.row.status === 'ready' &&
                    progressArr[scope.$index] === 0
                  "
                  >等待上传
                </span>
                <span
                  v-else-if="
                    progressArr[scope.$index] > 0 &&
                    progressArr[scope.$index] !== 100
                  "
                  >正在上传
                </span>
                <span v-else-if="progressArr[scope.$index] === 100"
                  >上传成功
                </span>                
              </template>
            </el-table-column>
            <el-table-column label="APT组织" align="center">
              <template slot-scope="scope">
                <el-select
                  v-model="apt[scope.$index].apt"
                  placeholder="请选择或搜索APT"
                  clearable
                  filterable
                  @change="changeApt($event, scope.$index)"
                >
                  <el-option
                    v-for="item in aptsArr"
                    :key="item.id"
                    :label="item.name"
                    :value="item.name"
                  >
                  </el-option>
                </el-select>
              </template>
            </el-table-column>
            <el-table-column prop="date" label="描述" align="center">
              <template slot-scope="scope">
                <el-input
                  v-model="apt[scope.$index].des"
                  placeholder="请输入描述"
                  clearable
                  @input="changeInput($event, scope.$index)"
                ></el-input>
              </template>
            </el-table-column>
            <el-table-column label="封面" align="center">
              <template slot-scope="scope">
                <el-upload
                  class="avatar-uploader"
                  action="你的上传地址"
                  :headers="{ 'x-auth-token': token }"
                  :show-file-list="false"
                  :on-success="handleLogoSuccess"
                  :before-upload="beforeLogoUpload"
                >
                  <el-button plain @click="curRowIndex = scope.$index">
                    <span v-if="!apt[scope.$index].logo">
                        <i class="el-icon-upload"></i>
                        上传封面
                    </span>
                    <span v-else>重新上传</span>
                  </el-button>
                </el-upload>
              </template>
            </el-table-column>
            <el-table-column
              label="操作"
              align="center"
              width="120px"
              show-overflow-tooltip
            >
              <template slot-scope="scope">
                <el-button
                  size="mini"
                  type="danger"
                  class="el-icon-delete"
                  @click="handleDelete(scope.$index, scope.row)"
                  >删除</el-button
                >
              </template>
            </el-table-column>
          </el-table>
        </div>
        <el-button
          style="margin-left: 10px"
          type="success"
          @click="submitUpload"
          >开始上传
        </el-button>
      </el-upload>
    </div>
  </div>
</template>

 2. Skriptcode

<script>
import axios from "axios";
import { findAptsAll } from "../../api/ttp.js";//这里是获取下拉框里面的选项
export default {
  name: "uploadReports",
  data() {
    return {
      token: sessionStorage.token,
      curRowIndex: 0,
      aptsArr: [],//下拉框选项
      fileList: [],//文件上传的列表
      apt: [], //这是是我接触到需要多传递的给后端的参数
      timer: null,//定时器的返回值
      progressArr: [],//控制进度条的进度
      statusArr: [],//控制文件上传的状态
    };
  },
  async created() {
    let { data } = await findAptsAll({ limit: 1000, page: 1 });
    this.aptsArr = data.data;
  },
  methods: {
    handleDelete(index, row) { //删除操作
      this.fileList.splice(index, 1);
      this.apt.splice(index, 1);
      this.progressArr.splice(index, 1);
      this.statusArr.splice(index,1)
    },
    changeFile(file, fileList) { 
      this.fileList = fileList.map((item, index) => {
        if (typeof item.size === "number") {
          this.apt[index] = { fileName: item.name, apt: "", logo: "", des: "" };
          this.progressArr[index] = 0;
          this.statusArr[index] = '上传成功'
          let str = item.size / 1024 + "";
          let arr = str.split(".");
          return {
            ...item,
            size: [arr[0], arr[1].slice(0, 1)].join(".") + "kb",
          };
        } else {
          return item;
        }
      });
    },
    submitUpload() {
      this.$refs.upload.submit();
    },
    handleLogoSuccess(res, file) {
      this.$message.success("封面上传成功!");
      this.apt = this.apt.map((item, index) => {
        if (index === this.curRowIndex) {
          return {
            ...item,
            logo: res.data,
          };
        } else {
          return item;
        }
      });
    },
    beforeLogoUpload(file) { //上传时的封面类型、大小控制
      const isJPG = file.type === "image/jpeg" || "image/png";
      const isLt10M = file.size / 1024 / 1024 < 10;

      if (!isJPG) {
        this.$message.error("上传封面只能是 JPG 或 PNG 格式!");
      }
      if (!isLt10M) {
        this.$message.error("上传封面大小不能超过 10MB!");
      }
      return isJPG && isLt10M;
    },
    uploadReport() { //由于submit()会触发多次自定义的http-request的方法,如果不加定时器控制的话,会重复触发上传
      if (this.timer) {
        clearTimeout(this.timer);
        this.timer = null;
      }
      this.timer = setTimeout(() => {
        this.fileList.forEach((item, index) => {
          this.statusArr = this.statusArr.map(item=>'上传成功')//为了使得上传失败,修改后正常上传时的上传状态可以更改
          let formData = new FormData();
          formData.append("file", item.raw);
          formData.append("apt", JSON.stringify(this.apt));
          axios({
            url: "上传路径",
            method: "post",
            data: formData,
            headers: {
              "Content-Type":
                "multipart/form-data; boundary=----WebKitFormBoundarynl6gT1BKdPWIejNq",
              "x-auth-token": sessionStorage.token,
            },
            onUploadProgress: (progressEvent) => {//axios自带可以获取到文件上传是的进度,可以直接用
              let num =
                ((progressEvent.loaded / progressEvent.total) * 100) | 0;
              this.progressArr = this.progressArr.map((item, ind) => {
                if (ind === index) {
                  return num;
                } else {
                  return item;
                }
              });
            },
          }).then(({ data }) => {
            this.statusArr = this.statusArr.map((item, ind) => {
              if (ind === index && data.code!==0) {
                return data.msg;
              } else {
                return item;
              }
            });
          });
        });
      }, 100);
    },
    changeApt(val, index) {
      this.apt = this.apt.map((item, ind) => {
        if (ind === index) {
          return { ...item, apt: val };
        } else {
          return item;
        }
      });
    },
    changeInput(val, index) {
      this.apt = this.apt.map((item, ind) => {
        if (ind === index) {
          return { ...item, des: val };
        } else {
          return item;
        }
      });
    },
  },
};
</script>

Beachten:

        Da bei der Bearbeitung aller Informationen alle Referenzdatentypen (Arrays) verwendet werden, müssen die Werte jedes Mal neu zugewiesen werden (aus diesem Grund liegen die Zuweisungen auf der Seite in Form einer Karte vor), um sicherzustellen, dass die Seite normal gerendert werden kann .

Supongo que te gusta

Origin blog.csdn.net/LaityMm/article/details/121947937
Recomendado
Clasificación