【sgUploadList】自定义组件:基于elementUI的el-upload封装的上传列表组件,适用于上传附件时

sgUploadList源码

html 复制代码
<template>
  <div :class="$options.name">
    <ul class="files">
      <li v-for="(a, i) in files" :key="i">
        <el-link @click.stop="clickFile(a)">
          <img :src="getFlieThumbSrc(a)" />
          <span>附件{{ i + 1 }}:{{ a.name }}</span></el-link
        >
        <el-link
          class="remove-btn"
          v-if="!disabled"
          icon="el-icon-close"
          :underline="false"
          @click.stop="remove(a, i)"
        />
      </li>
    </ul>

    <el-upload
      v-if="!disabled"
      :action="'#'"
      :auto-upload="false"
      :disabled="disabled"
      :multiple="true"
      :on-change="change"
      :show-file-list="false"
    >
      <el-button slot="trigger" type="primary" icon="el-icon-upload2">上传文件</el-button>
      <el-alert
        style="margin-top: 10px"
        :closable="true"
        :close-text="``"
        :description="``"
        :effect="'light'"
        :show-icon="true"
        :title="alertMsg || `最多可上传${limit}个附件,每个附件大小不超过${maxSize}M`"
        :type="'warning'"
      />
    </el-upload>

    <el-image ref="image" style="display: none" src="" :preview-src-list="[previewSrc]" />
  </div>
</template>
<script>
export default {
  name: "sgUploadList",
  components: {},
  data() {
    return {
      suffixIconURLs: this.$global.resourceTypes.flatMap((v) => v.suffixIconURLs),
      accept: `*`,
      form: {}, //表单信息
      disabled: false, //是否只读
      alertMsg: ``,
      limit: 10,
      maxSize: 400,
      files: [],
      previewSrc: null,
    };
  },
  props: ["data"],
  watch: {
    data: {
      handler(newValue, oldValue) {
        // console.log(`深度监听${this.$options.name}:`, newValue, oldValue);
        if (Object.keys(newValue || {}).length) {
          this.form = JSON.parse(JSON.stringify(newValue));
          this.disabled = this.form.disabled;
          this.alertMsg = this.form.alertMsg;
          this.files = this.form.files || [];
          this.form.accept && (this.accept = this.form.accept);
          this.form.limit && (this.limit = this.form.limit);
          this.form.maxSize && (this.maxSize = this.form.maxSize);
        } else {
          this.form = {
            // 默认字段名: 缺省值,
          };
        }
      },
      deep: true, //深度监听
      immediate: true, //立即执行
    },
  },
  methods: {
    change(file) {
      this.files.push(file.raw);
      if (this.files.length > this.limit) {
        this.$message(`最多只能上传${this.limit}个文件`);
        this.files = this.files.slice(0, this.limit);
      }
      this.$emit(`change`, { files: this.files });
    },
    remove(d, i) {
      this.files.splice(i, 1);
    },
    getSuffixByFileName(name) {
      return name.split(".").slice(-1)[0];
    },
    getFileTypeBySuffix(suffix) {
      return (this.$global.resourceTypes.find((v) => v.suffixs.includes(suffix)) || {})
        .type;
    },
    // 获取文件格式图片路径
    getFlieThumbSrc(d) {
      let rpnull = `~@/../static/img/fileType/other/rpnull.svg`;
      if (d) {
        typeof d === `string` && (d = JSON.parse(d));
        if (Object.keys(d || {}).length) {
          return this.suffixIconURLs.find((v) =>
            v.includes(`/${this.getSuffixByFileName(d.name)}.`)
          );
        } else return rpnull;
      } else return rpnull;
    },
    showImage(previewSrc) {
      this.previewSrc = previewSrc;
      this.$refs.image.showViewer = true; //显示大图
    },
    clickFile(d) {
      let isImage = false;
      if (d.fileURL) {
        isImage =
          this.getFileTypeBySuffix(this.getSuffixByFileName(d.name)) === `picture`;
        isImage ? this.showImage(d) : window.open(`${d.fileURL}`, "_blank");
      } else {
        isImage = d.type.includes(`image`);
        isImage
          ? this.$g.file2Base64Image(d, (d) => this.showImage(d))
          : this.$g.downloadByFileObject(d);
      }
    },
  },
};
</script>
<style lang="scss" scoped>
.sgUploadList {
  .files {
    li {
      margin-bottom: 10px;
      line-height: normal;
      width: max-content;
      max-width: 100%;
      .remove-btn {
        transition: 0.382s;
        opacity: 0;
        pointer-events: none;
        transform: translateX(-100%);
      }
      &:hover {
        .remove-btn {
          opacity: 1;
          pointer-events: auto;
          transform: translateX(0%);
        }
      }

      >>> .el-link {
        transition: 0.2s;
        line-height: normal;
        img {
          width: 16px;
          height: 16px;
          object-position: center;
          object-fit: contain;
          transform: translateY(2px);
        }
      }
    }
  }
  .el-alert {
    line-height: normal;
  }
}
</style>

应用

html 复制代码
<sgUploadList
  :data="{
    files: convertBackendFiles(form.FILE_INFO_LIST || []),
    disabled: disabled_,
    limit: 10,
  }"
  @change="getUploadFiles"
/>


...


getUploadFiles({ files }) {
  this.files = files;
},
相关推荐
Yolo@~4 小时前
个人网站:基于html、css、js网页开发界面
javascript·css·html
斯~内克4 小时前
Electron 菜单系统深度解析:从基础到高级实践
前端·javascript·electron
清风絮柳4 小时前
51. “闲转易”交易平台小程序(基于springboot&vue)
vue.js·spring boot·小程序·毕业设计·校园二手交易平台·二手交易小程序·闲转易交易系统
dr李四维4 小时前
vue生命周期、钩子以及跨域问题简介
前端·javascript·vue.js·websocket·跨域问题·vue生命周期·钩子函数
旭久4 小时前
react+antd中做一个外部按钮新增 表格内部本地新增一条数据并且支持编辑删除(无难度上手)
前端·javascript·react.js
朴拙数科6 小时前
技术长期主义:用本分思维重构JavaScript逆向知识体系(一)Babel、AST、ES6+、ES5、浏览器环境、Node.js环境的关系和处理流程
javascript·重构·es6
拉不动的猪6 小时前
vue与react的简单问答
前端·javascript·面试
旭久7 小时前
react+antd封装一个可回车自定义option的select并且与某些内容相互禁用
前端·javascript·react.js
阿丽塔~7 小时前
React 函数组件间怎么进行通信?
前端·javascript·react.js