el-upload基础封装,防止图片跳跃,限制上传数为1,

话不多说 直接上代码 首先是template层

el-upload上层div,通过自写图片样式效果,解决图片跳变问题,即不展示图片本身的file,只展示父组件传来的数据信息;
其中 :show-file-list=“false” 一定设置为false;
设置以后 :before-upload=“handleBeforeUpload” 会不生效,所以这部分逻辑在 :show-file-list="false"就不用看了;

:class="{ disUoloadSty:noneBtnImg }" 解决上传数为1的时候,不显示上传按钮问题;

:auto-upload=“false” 一般默认启用此属性,不自动上传文件,通过onchange来触发上传动作,顺便检测类型,确认上传大小等操作;

预览的时候 dialog 如果是第二层 append-to-body加上这个属性,否则蒙层会有问题;

<template>
  <div class="upload">
     <div class="d-flex flex-warp">
       <div
         v-for="(item,index) in allFileList"
         :key="index"
         class="picture-card-class m-r-10 m-b-10"
       >
         <img
           :src="item.url"
           alt=""
         >
         <div class="cover d-flex j-c-around f-s-12">
           <div class="vertical">
             <i
               class="el-icon-zoom-in"
               @click="handlePictureCardPreview(item)"
             />
           </div>
           <div v-if="!$attrs.disabled">
             <i
               class="el-icon-delete"
               @click="handleRemove(item)"
             />
           </div>
         </div>
       </div>
       <el-upload
         :class="{ disUoloadSty:noneBtnImg }"
         list-type="picture-card"
         :disabled="$attrs.disabled"
         :file-list="allFileList"
         :on-preview="handlePictureCardPreview"
         :on-remove="handleRemove"
         :before-upload="handleBeforeUpload"
         :limit="uploadOne ? 1: ''"
         action="/"
         :auto-upload="false"
         :show-file-list="false"
         :on-change="(file, fileList) => handleOtherChange(file, fileList)"
         :on-exceed="handleExceed"
       >
         <i class="el-icon-plus" />
       </el-upload>
     </div>
     <el-dialog
       class="preview-dialog"
       :visible.sync="dialogVisible"
       append-to-body
     >
       <img
         width="100%"
         :src="dialogImageUrl"
         alt=""
       >
     </el-dialog>
  </div>
</template>
<script>
// 自己的上传方法
import {
  uploadFile,
} from '@/api/restfulApi';
import _ from 'lodash';
import { matchType } from '@/utils/index';

export default {
  props: {
    // 上传文件格式限制
    uploadFileTypeArr: {
      type: Array,
      default: () => (
        ['pdf', 'doc', 'docx', 'jpg', 'png', 'xlsx', 'xls']
      ),
    },
    uploadOne: {
      type: Boolean,
      default: false,
    },
    type: {
      type: String,
      default: 'image',
    },
    parameterForm: {
      type: String,
      default: 'Array',
    },
  },
  data() {
    return {
      // 总文件信息
      allFileList: [],
      fileForm: {},
      dialogImageUrl: '',
      dialogVisible: false,
      disabled: false,
    };
  },
  computed: {
    noType() {
      const deepCloneList = _.cloneDeep(this.allFileList);
      const noType = deepCloneList.map((item) => {
        item.fileName = item.fileName.split('.')[0];
        return item;
      });
      return noType;
    },
    // 动态切换样式
    noneBtnImg() {
      return this.uploadOne && this.allFileList.length === 1;
    },
  },
  watch: {
  	//解决当前数据格式问题,可以为字符串 也可以 是数组;
    '$attrs[file-list]': {
      handler(val) {
        const value = this.$attrs['file-list'];
        // 处理数据信息,如果图片为数据,采用这种初始化
        if (this.parameterForm === 'Array' && value.length) {
          this.allFileList = value.map((item) => {
            item.url = item.fileUrl;
            return item;
          });
        }
        if (this.parameterForm === 'String' && value) {
        // 如果数据是字符串采用split+,处理。
          const list = value.split(',');
          this.allFileList = list.map((item) => {
            const obj = {};
            obj.fileName = item;
            obj.fileId = item;
            obj.url = this.getUrl(item);
            return obj;
          });
        }
      },
      immediate: true,
    },
  },
  methods: {
    /**
     * 解决只上传一个提示,且已经有一个图片的情况下的问题
     */
    handleBeforeUpload(file) {
      const fileName = file.name.split('.')[0];
      const splitIndex = file.name.lastIndexOf('.');
      const type = file.name.substring(splitIndex + 1, file.name.length).toLowerCase();

      const uploadOneflag = this.uploadOne && this.allFileList.length === 1;
      const fileSizeFlag = file.size > 1024 * 1024 * 300;
      const typeFlag = !this.uploadFileTypeArr.includes(type);
      const nameFlag = this.noType.some(ele => ele.fileName === fileName);
      console.log(uploadOneflag, fileSizeFlag, typeFlag, nameFlag);

      if (uploadOneflag) {
        this.$message.error('限制文件上传为1张');
      }
      // 文件超过大小进行提示
      if (fileSizeFlag) {
        this.$message.warning('上传文件超过300M,请联系管理员!');
      }
      // 判断文件类型,非指定类型禁止上传
      if (typeFlag) {
        this.$message({
          type: 'warning',
          message: `禁止上传该种类型文件,支持上传文件类型:${this.uploadFileTypeArr.join(' ')}`,
        });
      }
      if (nameFlag) {
        this.$message.error(`${fileName}文件重复上传!`);
      }
      return !(uploadOneflag || fileSizeFlag || typeFlag || nameFlag);
    },
    /**
     * 删除逻辑,暂时只考虑当前假删情况,可以记录删除id最后保存的时候,一起提交。
     */
    handleRemove(file, fileList) {
      const ind = this.allFileList.findIndex(ele => ele.fileName === file.fileName);
      this.allFileList.splice(ind, 1);
      this.handelUpdateVal();
    },
    handleExceed() {
      this.$message.warning('当前限制上传 1 个文件');
    },
    /**
     * 查看预览图片信息
     */
    handlePictureCardPreview(file) {
      this.dialogImageUrl = file.url;
      this.dialogVisible = true;
    },
    // 上传成功后往addFileList里面插入一个新文件
    handleOtherChange(file, fileList) {
      const fileName = file.name.split('.')[0];
      const allFilter = this.noType.some(ele => ele.fileName === fileName);
      if (allFilter) {
        const index = fileList.findIndex(item => item.fileName === fileName);
        fileList.splice(index, 1);
        this.$message.error(`${fileName}文件重复上传!`);
        return;
      }
      // 文件超过大小进行提示
      if (file.size > 1024 * 1024 * 300) {
        this.$message.warning('上传文件超过300M,请联系管理员!');
        return;
      }
      this.handleChange(file, fileList);
    },
    // 上传状态时 || 文件改变时
    handleChange(file, fileList) {
      // 判断文件类型,非指定类型禁止上传
      const splitIndex = file.name.lastIndexOf('.');
      const type = file.name.substring(splitIndex + 1, file.name.length).toLowerCase();
      // const uploadFileTypeArr = ['pdf', 'doc', 'docx', 'jpg', 'png', 'xlsx', 'xls'];
      if (this.uploadFileTypeArr.includes(type)) {
        this.fileForm.file = file.raw;
        const i = file.name.lastIndexOf('.');
        this.fileForm.fileName = file.name.substring(0, i);
        this.uploadFile();
      } else {
        const index = fileList.findIndex(item => item.name === file.name);
        // 删除当前选择的文件,使再次上传可以进行
        fileList.splice(index, 1);
        this.$message({
          type: 'warning',
          message: `禁止上传该种类型文件,支持上传文件类型:${this.uploadFileTypeArr.join(' ')}`,
        });
      }
    },
    /**
     * 拼接URL方法
     */
    getUrl(fileId) {
      return `${process.env.VUE_APP_FILE}/space/${fileId}/preview`;
    },
    // 上传文件
    uploadFile() {
      const formData = new FormData();
      Object.keys(this.fileForm).forEach((item) => {
        formData.append(item, this.fileForm[item]);
      });
      // 调上传文件的接口。上传到文件服务器获取文件id和name
      uploadFile(formData).then((res) => {
        const fileId = res.id;
        const fileName = res.originalName;
        const type = matchType(fileName);
        const obj = {
          fileId,
          fileName,
          type,
          valid: -1,
          src: type,
          url: this.getUrl(fileId),
        };
        if (this.uploadOne) {
          this.allFileList = [];
          this.allFileList.push(obj);
        } else {
          this.allFileList.push(obj);
        }
        this.handelUpdateVal();
      })
        .catch(() => {})
        .finally(() => {
          this.fileLoading = false;
        });
    },
    // 处理传给父组件的值,并更新父组件的值
    handelUpdateVal() {
      let fileList = null;
      if (this.parameterForm === 'Array') {
        fileList = [];
        this.allFileList.forEach((item) => {
          fileList.push({ fileId: item.fileId, fileName: item.fileName, fileUrl: item.url });
        });
      }
      if (this.parameterForm === 'String') {
        const newList = this.allFileList.map(item => item.fileId);
        fileList = newList.join(',');
      }
      this.$emit('uploadVal', fileList);
    },
  },
};

export const matchType = (fileName) => {
  // 后缀获取
  let suffix = '';
  // 获取类型结果
  let result = '';
  try {
    const flieArr = fileName.split('.');
    suffix = flieArr[flieArr.length - 1].toLowerCase();
  } catch (err) {
    suffix = '';
  }
  // fileName无后缀返回 false
  if (!suffix) {
    result = false;
    return result;
  }
  // 图片格式
  const imglist = ['png', 'jpg', 'jpeg', 'gif'];
  // 进行图片匹配
  result = imglist.some(item => item === suffix);
  if (result) {
    result = 'image';
    return result;
  }
  // 匹配txt
  //   const txtlist = ['txt'];
  //   result = txtlist.some(item => item === suffix);
  //   if (result) {
  //     result = 'txt';
  //     return result;
  //   }
  // 匹配 excel
  const excelist = ['xls', 'xlsx'];
  result = excelist.some(item => item === suffix);
  if (result) {
    result = 'excel';
    return result;
  }
  // 匹配 word
  const wordlist = ['doc', 'docx'];
  result = wordlist.some(item => item === suffix);
  if (result) {
    result = 'word';
    return result;
  }
  // 匹配 pdf
  const pdflist = ['pdf'];
  result = pdflist.some(item => item === suffix);
  if (result) {
    result = 'pdf';
    return result;
  }
  // 匹配 ppt
  const pptlist = ['ppt', 'pptx'];
  result = pptlist.some(item => item === suffix);
  if (result) {
    result = 'ppt';
    return result;
  }
  // 匹配 视频
  //   const videolist = ['mp4', 'm2v', 'mkv'];
  //   result = videolist.some(item => item === suffix);
  //   if (result) {
  //     result = 'video';
  //     return result;
  //   }
  // 匹配 音频
  //   const radiolist = ['mp3', 'wav', 'wmv'];
  //   result = radiolist.some(item => item === suffix);
  //   if (result) {
  //     result = 'radio';
  //     return result;
  //   }
  // 匹配 压缩包
  const zipList = ['zip', 'rar'];
  result = zipList.some(item => item === suffix);
  if (result) {
    result = 'zip';
    return result;
  }
  // 匹配 视频
  const videoList = ['mp4', 'avi'];
  result = videoList.some(item => item === suffix);
  if (result) {
    result = 'video';
    return result;
  }
  // 其他 文件类型
  result = 'other';
  return result;
};
</script>
<style lang="scss" scoped>
.upload {
	// 默认图片展示样式,从el-upload扒过来的
  .picture-card-class {
    background-color: #fbfdff;
    border-radius: 6px;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    width: 148px;
    height: 148px;
    cursor: pointer;
    line-height: 146px;
    vertical-align: top;
    position: relative;
      img {
        width: 100%;
        height: 100%;
        object-fit: contain;
        border-radius: 6px;
        border: 1px solid #ffffff;
      }
      // 这部分是鼠标移动 图片显示蒙层的方法,在图片div上附着一层div,平时透明度为0,指上后显示0.7
      .cover {
        top: 0px;
        width: 100%;
        height: 100%;
        text-align: center;
        position: absolute;
        border-radius: 6px;
        background-color: rgba(0, 0, 0, 0.5);
        opacity: 0;
      }

      /* 鼠标hover,显示遮罩,设置过渡时间 */
      .cover:hover  {
        transition: all 0.5s;
        color: #ffffff;
        width: 100%;
        height: 100%;
        opacity: 0.7;
      }
  }
}
</style>

<style lang="scss">
.disUoloadSty .el-upload--picture-card {
  display:none;   /* 文件上传隐藏 */
}
</style>

以上就是el-upload我的一些封装小建议,感觉还是不够好,只是凑合能用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值