likes
comments
collection
share

基于element UI封装一个上传组件

作者站长头像
站长
· 阅读数 11

之前写了一个上传组件,最近要改成上传到云端桶里,本来只是改一个上传接口,但打开看了一眼以前写的上传组件,真的稀碎,于是重新实现一遍。

在项目中,用上传组件的大部分情况,都是picture-card,5%的其他展示形式。所以主要是针对pictrue-card展示形式的处理,其他的开放插槽让用的人自己细细处理。

之前的上传组件,有特别多props,在此方案中,尽量不要加props,传参理解起来需要时间,会增加使用成本,能用slot替代,就用slot。

组件构成

所以,组件计划支持

① 上传区域开插槽,支持用户使用者自定义上传区域的展示内容;若不用插槽,则展示默认的内容;默认内容支持用插槽替换局部

② 展示区域开插槽,支持用户自定义上传文件后的展示形式;若不用插槽,则展示默认的内容

③ 支持只读模式,不允许上传

④ 支持文件预览:图片用v-viewer;非弹窗打开新页面看,不支持的话浏览器会自动下载

⑤ 图片卡片模式(picture-card)展示文件名

⑥ 基础内容和上传方法单独抽成一个js文件存放,上传组件里只放它自己的逻辑

默认内容介绍:

默认使用加号的图标,带插槽uploadText支持拖拽区输入文字

基础展示

未加修饰的上传组件,listtype的三种展示形式如下:

图片picture 上传文件后,一个一行,自带边框。

基于element UI封装一个上传组件

图片卡片picture-card上传文件后,多个一行,无文件名,需要支持展示。

基于element UI封装一个上传组件

文字text 上传文件后,一个一行。 基于element UI封装一个上传组件

根据设计方案实现

上传区域支持插槽

定义了插槽uploadBox。若没使用插槽uploadBox,则展示默认内容。

<!-- 上传区域 -->
<template v-if="!$slots.uploadBox">
  <i class="el-icon-plus"></i>
  <div class="el-upload__text">
    <!-- 若有想展示在组件拖拽区的文字,请使用此插槽 -->
    <slot name="uploadText" />
  </div>
</template>
<!-- 自定义上传区域内容 -->
<slot v-else name="uploadBox" />

补一下上传的小问题,在data中定义fileList,给el-upload上传组件用(data() { fileList: [] })。数据并不是双向绑定的,需要在上传成功后,自己推入fileList中,this.fileList.push(file)

    // 上传成功,抛出文件给父组件
    async handleSuccess (response, file, fileList) {
      await afterSuccess(response, file, fileList);
      this.$emit("afterUplod", file);
      this.fileList.push(file)
    },
内容区域支持插槽

定义了插槽uploadContent。若没有使用插槽uploadContent,则展示默认内容。 若不想展示文件列表,就使用插槽,但不传内容。

经过试验,直接定义插槽uploadContent,不行~

el-upload的内容区域,要通过它的插槽去file去修改~ 所以,微微调整一下~

<!-- 内容区域,只对图片卡片picture-card模式,做默认展示 -->
      <div
        v-if="!$slots.uploadContentBox && ['picture-card'].includes(listType)"
        slot="file"
        slot-scope="{ file }"
      >
        <img
          class="el-upload-list__item-thumbnail"
          :src="handleProcessImgUrl(file)"
          alt=""
        />
        <el-tooltip :content="file.name">
          <span v-if="isShowFileName" class="down-name">
            {{ file.name }}</span
          >
        </el-tooltip>
        <span class="el-upload-list__item-actions">
          <span
            class="el-upload-list__item-preview"
            @click="handlePreview(file)"
          >
            <i class="el-icon-zoom-in" />
          </span>
          <span
            v-if="!isDisabled"
            class="el-upload-list__item-delete"
            @click="handleRemove(file, true)"
          >
            <i class="el-icon-delete" />
          </span>
        </span>
      </div>
      <!-- 可自定义内容区域 -->
      <div
        v-else
        slot="file"
        slot-scope="{ file }"
      >
        <slot name="uploadContentBox" :file="file" />
      </div>


样式,隐藏上传按钮
:class="[
        classNameStr,
        { 'is-hide': fileList.length >= limit || isDisabled },
        { 'pic-wrapper': isShowFileName }
      ]"
抽离公共方法、变量定义

① 检查文件是否符合要求:格式、大小

② 上传成功后回调

③ 删除方法

④ 获取文件后缀之类的小方法

⑤ 其他方法,巴拉巴拉

抽离的内容放在upload.js里,简单贴两个方法供参考啦~

// 检查文件格式和文件大小
function checkFileTypeSize(rawFile, accept, maxSizeM ) {
  const acceptArr = filterValidArr(accept.split(","))
  const suffix = getSuffix(rawFile.name, true);

  if (acceptArr.length > 0 && !acceptArr.includes(suffix)) {

    tipMsgFun(`请上传需要的文件(${accept})`, 'warning')
    return false;
  } else if (!!maxSizeM && rawFile.size / 1024 / 1024 > maxSizeM) {

    tipMsgFun(`上传文件大小不能超过${maxSizeM}MB`, 'warning')
    return false;
  }
  return true;
}

function removeFile(fileList, file) {
  let delIdx = null;
  fileList.forEach((item, index) => {
    if (item.uid === file.uid) {
      delIdx = index;
    }
  });
  fileList.splice(delIdx, 1);
  return fileList
}

试了一下贴所有代码,太冗余了,不贴啦~

就酱紫,结束。

转载自:https://juejin.cn/post/7237009597583130681
评论
请登录