【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;
},
相关推荐
dsyyyyy11019 小时前
JavaScript变量
开发语言·javascript·ecmascript
kyriewen9 小时前
手写 Promise.all、race、any:不到 30 行代码,解决并发异步的所有姿势
前端·javascript·面试
胡志辉的博客11 小时前
深入浅出理解浏览器事件循环:从一道输出题讲到 Chrome 源码
前端·javascript·chrome·chromium·event loop
代码不加糖11 小时前
js中不会冒泡的事件有哪些?
前端·javascript·vue.js
懂懂tty11 小时前
Vue2与Vue3之间API差异
前端·javascript·vue.js
老毛肚12 小时前
软件测试期末考试
vue.js
小二·12 小时前
Next.js 15 全栈开发实战
开发语言·javascript·ecmascript
杨若瑜13 小时前
本地开发环境慢?localhost的锅!
vue.js
Rain50913 小时前
2.1 Nest.js 项目初始化与模块化架构
开发语言·前端·javascript·后端·架构·数据分析·node.js
拾年27514 小时前
从零手写 Ajax:用原生 XHR 搭建前后端交互全流程
前端·javascript·ajax