封装elementui上传组件upload单个图片或视频上传

3,010 阅读1分钟

场景

vue + elementUi框架做后台管理系统时,使用到elementui中的Upload组件做单张图片或单个视频上传时。官网提供了单张图片上传和多图片上传,在其基础上又封装了一下,加入了上传时的进度条显示以及单个视频上传,封装到了一个组件中。

代码

uploadFile.vue

<template>
  <div>
    <el-upload
      class="avatar-uploader"
      :action="uploadUrl"
      :headers="{ Authorization: token }"
      :show-file-list="false"
      :on-success="handleSuccess"
      :before-upload="beforeUpload"
      :on-progress="uploadProcess"
    >
      <div v-if="!fileFlag && fileType === 'image'">
        <img v-if="fileUrl" :src="fileUrl" class="avatar" />
        <i v-else class="el-icon-plus avatar-uploader-icon" />
      </div>
      <div v-if="!fileFlag && fileType === 'video'">
        <video
          v-if="fileUrl"
          :src="fileUrl"
          class="avatar-video"
          controls="controls"
        >
          您的浏览器不支持视频播放
        </video>
        <i v-else class="el-icon-plus avatar-uploader-icon" />
      </div>
      <el-progress
        v-if="fileFlag"
        style="margin-top:10px;"
        type="circle"
        :percentage="uploadPercent"
      />
    </el-upload>
  </div>
</template>
<script>
export default {
  props: {
    token: {
      type: String,
      default: ""
    },
    uploadUrl: {
      type: String,
      required: true
    },
    fileType: {
      type: String,
      default: "image"
    }
  },
  data() {
    return {
      fileUrl: "",  // 上传成功后接口返回的地址
      uploadPercent: 0,  // 上传时进度条显示的进度
      fileFlag: false  // 显示文件还是进度条的标识
    };
  },
  methods: {
    // 上传成功的回调
    handleSuccess(res, file) {
      this.fileFlag = false;
      this.uploadPercent = 0;
      if (res.code === 200) {
        this.fileUrl = res.data;
      } else {
        this.$message.error("视频上传失败,请重新上传!");
      }
    },
    // 进度条
    uploadProcess(event, file, fileList) {
      this.fileFlag = true;
      this.uploadPercent = Math.floor(event.percent);
    },
    beforeUpload(file) {
        // 先空着在下面优化,对上传格式的限制,需要动态判断
    }
  }
};
</script>

props中的tokenuploadUrl根据需要在父组件中传入,因为有时候后台接口要求上传文件时 需要在请求头headers里加入登录标识token,uploadUrl为上传文件的接口。fileType传入imagevideo,在视图中就根据fileType判断显示img图片标签还是video视频标签。

data中的字段含义可以在注释中看到。 下面是css代码:

<style lang="scss" scope>
.avatar-uploader .el-upload {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.avatar-uploader .el-upload:hover {
  border-color: #409eff;
}
.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 148px;
  height: 148px;
  line-height: 148px;
  text-align: center;
}
.avatar {
  width: 148px;
  max-height: 148px;
  display: block;
}
.avatar-video {
  width: 200px;
  max-height: 200px;
  display: block;
}
</style>
  • 在父组件parent.vue中使用uploadFile.vue上传图片或视频 parent.vue
<uploadFile
    :token="token"
    :upload-url="uploadUrl"
    file-type="video"
/>
<script>
    import uploadFile from "./uploadFile.vue";
    export default {
        components: { uploadFile },
        data() {
            return {
                token: "token123",
                uploadUrl: process.env.VUE_APP_BASE_API + "/file/upload"
            }
        }
    }
</script>

tokenuploadUrl换成自己的就可以使用上传功能了,file-type不传值就默认为 "image"。下面开始优化代码:

  • 防止用户在传图片的地方上传了视频或其他文件,加入限制文件格式的代码 在 uploadFile.vue 中加入
    beforeUpload(file) {
      const isImage =
        file.type === "image/jpeg" ||
        file.type === "image/png" ||
        file.type === "image/jpg";
      const isVideo =
        file.type === "video/mp4" ||
        file.type === "video/avi" ||
        file.type === "video/flv";
      const isLt10M = file.size / 1024 / 1024 < 10;
      if (!isLt10M) {
        this.$message.error("上传文件大小不能超过 10MB!");
        return false;
      }
      if (!isImage && this.fileType === "image") {
        this.$message.error("上传文件格式有误!");
        return false;
      }
      if (!isVideo && this.fileType === "video") {
        this.$message.error("上传文件格式有误!");
        return false;
      }
    },
  • 如果需要回显,让子组件直接 uploadFile.vue 直接显示图片或视频,则再多加一个props参数。

父组件parent.vue中添加hasFile,如果需要回显直接传入需要回显的链接,不需要则为空

  <SingleImageUpload
    // ...
    :has-file="hasFile"
  />
  data() {
    return {
      // ...
      hasFile: ""
    };
  },

子组件uploadFile.vue中接收参数

  props: {
    // ...
    hasFile: {
      type: String,
      default: ""
    }
  },

子组件中使用watch监听,如果传入了值,就给fileUrl赋值传入的文件地址

  watch: {
    hasFile(val) {
      if (val) {
        this.fileUrl = val;
      } else {
        this.fileUrl = "";
      }
    }
  }