el-upload(element-plus)自定义图标组件封装

707 阅读2分钟

效果图

image.png

版本

  • vue: 3.2.37
  • element-plus: 2.2.14

代码(vue3)

  • UploadCustom.vue
<template>
  <el-upload
    :class="[props.uploadBtnShow ? '' : 'hidden-upload-btn']"
    action="#"
    :file-list="uploadFileList"
    list-type="picture-card"
    :multiple="props.multiple"
    :before-upload="beforeUpload"
    :accept="uploadAcceptFileType.join()"
    :on-change="uploadFileChange"
    :on-success="uploadFileSuccess"
    :http-request="customUploadFile"
    :auto-upload="true"
  >
    <template #file="{ file }">
      <div class="custom-file-cover flex flex-col items-center w-full">
        <img :src="uploadIconDics[file.raw.iconType]" width="60" class="mt-3" />
        <p class="el-upload-list__item-file-name mt-2 flex items-center text-12px">
          <span class="inline-block overflow-hidden whitespace-nowrap text-ellipsis max-w-72px">{{
            file.raw.frontName
          }}</span>
          <span>{{ '.' + file.raw.suffix }}</span>
        </p>
        <span class="el-upload-list__item-actions">
          <div v-if="file.status !== 'uploading'">
            <span class="el-upload-list__item-preview" v-if="props.previewBtnShow && !file.raw.previewBtnHidden">
              <el-icon @click="uploadFileHandler('preview', file)"><ZoomIn /></el-icon>
            </span>
            <span class="el-upload-list__item-delete" v-if="props.downBtnShow">
              <el-icon @click="uploadFileHandler('download', file)"><Download /></el-icon>
            </span>
            <span class="el-upload-list__item-delete" v-if="props.deleteBtnShow">
              <el-icon @click="uploadFileHandler('delete', file)"><Delete /></el-icon>
            </span>
          </div>
        </span>
      </div>
    </template>
    <div class="flex flex-col items-center">
      <el-icon :size="24"><Plus style="color: #1d1d1dff" /></el-icon>
      <p class="text-12px text-#00000066 mt-2">上传文件</p>
    </div>
  </el-upload>
  <el-empty :image-size="emptyImageSize" v-if="emptyShow && !props.uploadBtnShow && !uploadFileList.length" />
</template>
<script setup lang="ts">
import { ref, defineProps, defineEmits, watchEffect } from 'vue';
import { ElMessage } from 'element-plus';
import { downFileByAElement, beforeUploadHandler } from '@/utils/util';
import iconXls from '@/assets/img/icon-xls.png';
import iconPdf from '@/assets/img/icon-pdf.png';
import iconDoc from '@/assets/img/icon-doc.png';
import iconImg from '@/assets/img/icon-img.png';
import iconOther from '@/assets/img/icon-file.png';
import iconTxt from '@/assets/img/icon-txt.png';
import iconCsv from '@/assets/img/icon-csv.png';
import iconHtml from '@/assets/img/icon-html.png';

const props = defineProps({
  uploadFileList: {
    type: Array,
    required: true,
    default: [],
  },
  autoUpload: {
    type: Boolean,
    required: false,
    default: true,
  },
  uploadBtnShow: {
    type: Boolean,
    required: false,
    default: true,
  },
  downBtnShow: {
    type: Boolean,
    required: false,
    default: false,
  },
  deleteBtnShow: {
    type: Boolean,
    required: false,
    default: false,
  },
  previewBtnShow: {
    type: Boolean,
    required: false,
    default: false,
  },
  multiple: {
    type: Boolean,
    required: false,
    default: false,
  },
  emptyShow: {
    type: Boolean,
    required: false,
    default: false,
  },
  emptyImageSize: {
    type: Number,
    required: false,
    default: 96,
  },
});

const emit = defineEmits([
  'update:uploadFileList',
  'customUploadFile',
  'downUploadFile',
  'deleteUploadFile',
  'previewUploadFile',
  'uploadFileSuccess',
]);
const currentFile = ref([]);
const uploadFileList = ref([]);
const uploadFileListTemp = ref([]);
const uploadAcceptFileType = [
  '.doc',
  '.docx',
  '.xlsx',
  '.xls',
  '.txt',
  '.csv',
  '.png',
  '.jpg',
  '.gif',
  '.pdf',
  '.html',
];
const uploadIconDics = {
  xls: iconXls,
  pdf: iconPdf,
  doc: iconDoc,
  img: iconImg,
  other: iconOther,
  html: iconHtml,
  csv: iconCsv,
  txt: iconTxt,
};
const customUploadFile = () => {
  if (!props.autoUpload) return;
  emit('customUploadFile', currentFile.value, uploadFileList.value);
};

const uploadFileHandler = (flag, file) => {
  if (flag === 'delete') {
    let id = 'id';
    if (!file.id) {
      id = 'uid';
    }
    const index = uploadFileList.value.findIndex(item => item[id] === file[id]);
    if (index > -1) {
      uploadFileList.value.splice(index, 1);
    }
    if (!file.id) {
      const currentFile = uploadFileListTemp.value.find(item => item.affixName === file.name);
      if (!currentFile) return;
      file.id = currentFile.id;
    }
    emit('deleteUploadFile', file);
  } else if (flag === 'download') {
    if (file.id) {
      emit('downUploadFile', file);
    } else {
      downFileByAElement(file.url, file.name);
    }
  } else if (flag === 'preview') {
    let id = file.id;
    if (!id) {
      const currentFile = uploadFileListTemp.value.find(item => item.affixName === file.name);
      id = currentFile?.id;
    }
    if (!id) return;
    file.id = id;
    emit('previewUploadFile', file);
  }
};

const beforeUpload = (file, flag = false) => {
  beforeUploadHandler(file);
  if (flag) return;
  if (!uploadAcceptFileType.includes('.' + file.suffix)) {
    ElMessage.error('文件类型不支持');
    return false;
  } else if (file.size / 1024 / 1024 > 5) {
    ElMessage.error('文件大小不能超过5M');
    return false;
  }
};
const uploadFileSuccess = () => {
  emit('uploadFileSuccess');
};
const uploadFileChange = (file, files) => {
  emit('update:uploadFileList', files);
  uploadFileList.value = files;
  currentFile.value = file;
};

const init = list => {
  uploadFileList.value = list;
  uploadFileList.value.forEach((item: any) => {
    if (!item.affixName) return;
    item.name = item.affixName;
    const temp = {
      name: item.affixName,
    };
    beforeUpload(temp, true);
    item.raw = temp;
  });
};

watchEffect(() => {
  const list = props.uploadFileList;
  init(list);
});
</script>

<style scoped lang="less">
.hidden-upload-btn :deep(.el-upload) {
  display: none;
}

:deep(.el-upload-list) {
  .el-upload,
  .el-upload-list__item {
    width: 120px;
    height: 120px;
    border-style: dashed;
  }
}
</style>

</script>

<style scoped lang="less">
.hidden-upload-btn :deep(.el-upload) {
  display: none;
}

:deep(.el-upload-list) {
  .el-upload,
  .el-upload-list__item {
    width: 120px;
    height: 120px;
    border-style: dashed;
  }
}
</style>

  • @/utils/util.ts
export function getFileExtensionName(filename) {
  return filename.slice(((filename.lastIndexOf('.') - 1) >>> 0) + 2);
}

export function getFileFrontName(filename) {
  const index = filename.lastIndexOf('.');
  return filename.slice(0, index);
}

export function beforeUploadHandler(file) {
  const fileName = file.name;
  const type = getFileExtensionName(fileName);
  file.suffix = type;
  file.frontName = getFileFrontName(fileName);
  if (['xlsx', 'xls'].includes(type)) {
    file.iconType = 'xls';
    file.previewBtnHidden = true;
  } else if (['jpg', 'png', 'jpeg', 'gif', 'webp', 'svg'].includes(type)) {
    file.iconType = 'img';
  } else if (['pdf'].includes(type)) {
    file.iconType = 'pdf';
  } else if (['doc', 'docx'].includes(type)) {
    file.iconType = 'doc';
  } else if (['txt'].includes(type)) {
    file.iconType = 'txt';
  } else if (['htm', 'html'].includes(type)) {
    file.iconType = 'html';
  } else if (['csv'].includes(type)) {
    file.iconType = 'csv';
  } else {
    file.iconType = 'other';
  }
}

export function downFileByAElement(data, fileName?) {
  let url = null;
  if (typeof data === 'string') {
    url = data;
  } else {
    const blob = new Blob([data]);
    url = window.URL.createObjectURL(blob);
  }
  const a = document.createElement('a');
  a.href = url;
  if (fileName) {
    a.setAttribute('download', fileName);
  }
  a.click();
}

组件调用

<template>
    <UploadCustom
      :emptyShow="true"
      :uploadBtnShow="uploadBtnShow"
      v-model:uploadFileList="uploadFileList"
      :downBtnShow="true"
      :previewBtnShow="true"
      :deleteBtnShow="true"
      @previewUploadFile="previewUploadFile"
      @downUploadFile="downUploadFile"
      @deleteUploadFile="deleteUploadFile"
      @uploadFileSuccess="uploadFileSuccess"
      @customUploadFile="customUploadFile"
    ></UploadCustom>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import UploadCustom from '@/components/UploadCustom.vue'
const uploadBtnShow = ref(true)
const uploadFileList = ref([])
const customUploadFile = (file,files) => {
    // 自定义上传方法
  const uploadData={
      file:file.raw
  }
  uploadMetricsFileApi(uploadData)
};
const uploadFileSuccess = () => {
  // 上传成功回调
};

const previewUploadFile = file => {
 // 下载回调
};

const deleteUploadFile = file => {
  // 删除回调
   deleteUploadFileApi({ id: file.id });
};

const downUploadFile = file => {
// 下载回调
  const params = {
    id: file.id,
  };
  downloadUploadFileApi(params);
};
</script>

图标附件下载

问题

  • 评论留言

参考文档