多图上传可拖拽组件

HTML片段

<template>
  <div  class="image-list">
    <vuedraggable
      class="vue-draggable"
      :class="{ single: isSingle, maxHidden: isMaxHidden }"
      v-model="dataList"
      tag="ul"
      draggable=".draggable-item"
      @end="emitResult('draggable')"
    >
      <!-- @start="onDragStart"
      @end="onDragEnd" -->
      <!-- 拖拽元素 -->
      <li
        v-for="(item, index) in dataList"
        :key="index"
        class="draggable-item"
        style="width:146px;height:146px;"
      >
      <!-- :style="style" -->
        <div class="status-label">
          <i class="status-upload-success el-icon-check"></i>
        </div>
        <el-image :src="item.url" :preview-src-list="srcList"></el-image>
        <div class="shadow">
          <i class="el-icon-delete shadow-icon" @click="onRemoveHandler(item)"></i>
        </div>
      </li>
      <!-- 上传按钮 -->
      <el-upload
        ref="uploadRef"
        class="uploadBox"
        :class="options.hidePlus ? 'hide-plus' : ''"
        :style="style"
        :disabled="!!options.disabled"
        :file-list="dataList"
        action="https://jsonplaceholder.typicode.com/posts/"
        :headers="设置上传的请求头部"
        accept=".jpg,.jpeg,.png,.gif"
        :show-file-list="false"
        :multiple="!isSingle"
        :limit="limit"
        :list-type="options.listType || 'picture-card'"
        :http-request="options.httpRequest || httpRequest"
        :before-upload="options.beforeUpload || beforeUpload"
        :on-remove="options.onRemove || onRemove"
        :on-exceed="onExceed"
      >
        <i class="el-icon-plus uploadIcon">
          <span class="uploading" v-show="isUploading">正在上传...</span>
          <span
            v-if="!isUploading && limit && limit!==99 && !isSingle"
            class="limitTxt"
          >最多{{ limit }}张</span>
        </i>
      </el-upload>
    </vuedraggable>
  </div>
</template>

js片段

<script>
import { FileMx } from '@/mixins';
import { UNIT_PX } from '@/utils/adapter';
import vuedraggable from 'vuedraggable'
// import draggable from 'vuedraggable'
import { SERVER_FILE_API } from '@/config/config';
import { mapState, mapGetters } from 'vuex';
import { upLoadFile } from '@/api/UpLoadApi';

export default {
  name: 'UploadDraggable',
    mixins: [FileMx],

  props: {
        options: {
            type: Object,
            default: () => ({})
        },
        fileList: {
            // type: [Array, String]
        },
        // 后端各模块前缀
        URL: {
            type: String,
            default: ''
        },
    // 图片数据(图片url组成的数组) 通过v-model传递
    // value: {
    //   type: Array,
    //   default () {
    //     return []
    //   }
    // },
    // 限制上传的图片数量
    limit: {
      type: Number,
      default: 99
    },
    // 限制上传图片的文件大小(kb)
    size: {
      type: Number,
      default: 500
    },
    // 是否是单图上传(单图上传就是已传图片和上传按钮重叠)
    isSingle: {
      type: Boolean,
      default: false
    },
    // 是否使用图片压缩
    useCompress: {
      type: Boolean,
      default: false
    },
    // 图片显示的宽度(px)
    // width: {
    //   type: Number,
    //   default: 100
    // },
    // // 图片显示的高度(px)
    // height: {
    //   type: Number,
    //   default: 100
    // }
  },

  data () {
    return {
        // 拖拽时显示的列表

        list:[1,2,3,4,5,],
            style: {
                width: this.options.width || 200 + UNIT_PX,
                height: this.options.height || 200 + UNIT_PX,
                overflow: 'auto'
            },
            isUploading: false, // 正在上传状态
            isFirstMount: true // 控制防止重复回显
    }
  },

  computed: {
        ...mapState(['authorizationHeader', 'uploadFileApi']),
        // dataList() {
        // debugger;
        //     console.log('========')
        //     // 如果是字符串或者空
        //     if (!this.fileList || typeof this.fileList === 'string') {
        //         if (this.fileList)
        //             return this.fileList.split(',').map(item => {
        //                 return { name: item, url: SERVER_FILE_API + item };
        //             });
        //     } else {
        //         return this.fileList;
        //     }
        //     return [];
        // },
        dataList: {
            get: function () {
                // 如果是字符串或者空
                if (!this.fileList || typeof this.fileList === 'string') {
                    if (this.fileList)
                        return this.fileList.split(',').map(item => {
                            return { name: item, url: SERVER_FILE_API + item };
                        });
                } else {
                    return this.fileList;
                }
                return [];
            },
            set: function (newValue) {
                this.$emit('update:fileList', newValue);
            }
        },
        srcList() {
            console.log("+++++++++==")
            return this.dataList.map(item => item.url);
        },
    // 控制达到最大限制时隐藏上传按钮
    isMaxHidden () {
        console.log("isMaxHidden")
      return this.dataList.length >= this.limit
    }
  },

  watch: {
    // value: {
    //   handler (val) {
    //     if (this.isFirstMount && this.value.length > 0) {
    //       this.syncElUpload()
    //     }
    //   },
    //   deep: true
    // }
  },

  mounted () {
    // if (this.value.length > 0) {
    //   this.syncElUpload()
    // }
  },

  methods: {
        ...mapGetters(['getToken2']),
    // 同步el-upload数据
    syncElUpload (val) {
    //   const imgList = val || this.imgList
    //   this.$refs.uploadRef.uploadFiles = imgList.map((v, i) => {
    //     return {
    //       name: 'pic' + i,
    //       url: v,
    //       status: 'success',
    //       uid: tools.createUniqueString()
    //     }
    //   })
    //   this.isFirstMount = false
    },
    // 上传图片之前
    beforeUpload (file) {
            // 更改验证类型
            if (file.type.indexOf('jpeg') !== -1||file.type.indexOf('png') !== -1) {
                return true;
            }
            this.$message.error('确保为图片类型!');
            return false;
    //   this.isFirstMount = false
    //   if (this.useCompress) {
    //     // 图片压缩
    //     return new Promise((resolve, reject) => {
    //       lrz(file, { width: 1920 }).then((rst) => {
    //         file = rst.file
    //       }).always(() => {
    //         if (validImgUpload(file, this.size)) {
    //           this.isUploading = true
    //           resolve()
    //         } else {
    //           reject(new Error())
    //         }
    //       })
    //     })
    //   } else {
    //     if (validImgUpload(file, this.size)) {
    //       this.isUploading = true
    //       return true
    //     } else {
    //       return false
    //     }
    //   }
    },
        /**
         * 成功回调
         * @param res
         * @param file
         */
    // 上传完单张图片
    onSuccess (res, file, fileList) {
            // 加100400提示
            if(res.code==100400){
                this.$message.error(res.msg)
                return false
            }
            // this.imgUrl = URL.createObjectURL(file.raw);
            // this.$emit('update:imgUrl', res.data);

      // 这里需要根据你自己的接口返回数据格式和层级来自行修改
    //   if (res.files) {
    //       // 判断接口上传成功
    //     if (this.imgList.length < this.limit) {
    //       // 未超限时,把接口返回的图片url地址添加到imgList
    //       this.imgList.push(res.files.file)
    //     }
    //   } else {
    //       // 判断接口上传失败
    //     this.syncElUpload()
    //     this.$message({ type: 'error', message: res.msg })
    //   }
    //   this.isUploading = false
    },
    
    onRemove(item) {
        console.log("onRemove")
        this.dataList.splice(
            this.dataList.findIndex(o => o.name === item.name),
            1
        );
        this.emitResult();
    },
    // 通知父级
    emitResult(val) {
        console.log(typeof this.fileList === 'string',"emitResult")
        // 如果是字符串或者空
        if (!this.fileList || typeof this.fileList === 'string'||val=='draggable') {
            console.log('111111111111')
            this.$emit(
                'update:fileList',
                this.dataList.map(item => item.url.replace(SERVER_FILE_API, '')).join(',')
            );
        } else {
            this.$emit('update:fileList', this.fileList);
        }
    },
    // 移除单张图片
    onRemoveHandler (item) {
      console.log(item,78787878987)
      this.dataList.splice(
          this.dataList.findIndex(o => o.name === item.name),
          1
      );
      this.emitResult();
    //   this.$confirm('确定删除该图片?', '提示', {
    //     confirmButtonText: '确定',
    //     cancelButtonText: '取消',
    //     type: 'warning'
    //   })
    //     .then(() => {
    //       this.imgList = this.imgList.filter((v, i) => {
    //         return i !== index
    //       })
    //     })
    //     .catch(() => {})
    },
    // 超限
    onExceed () {
    //   this.$refs.uploadRef.abort() // 取消剩余接口请求
    //   this.syncElUpload()
    //   this.$message({
    //     type: 'warning',
    //     message: `图片超限,最多可上传${this.limit}张图片`
    //   })
    },
    onDragStart (e) {
        console.log(e,22222222222);
      e.target.classList.add('hideShadow')
    },
    onDragEnd (e) {
        console.log(e,'-----------')
      e.target.classList.remove('hideShadow')
    },
    
    // 完成上传
    httpRequest(res) {
        console.log("httpRequest")
        upLoadFile.call(this, res, res => {
            let fileName = res.data.data;
            this.dataList.push({
                name: fileName,
                url: SERVER_FILE_API + fileName
            });
            this.emitResult();
        });
    },
  },

  components: { 
      vuedraggable,
    //   draggable
 }
}
</script>

样式

<style lang="scss" scoped>

// 隐藏添加图标
.hide-plus {
    & ::v-deep .el-upload--picture-card {
        display: none;
    }
}
.image-list {
  margin-left: 20px;
    & /deep/ .el-icon-circle-close:before {
        color: #fff;
    }
}

/deep/ .el-upload {
  width:150px;
  height:150px;
//   width: 100%;
//   height: 100%;
}

// 上传按钮
.uploadIcon {
  width: 100%;
  height: 100%;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px dashed #c0ccda;
  background-color: #fbfdff;
  border-radius: 6px;
  font-size: 28px;
  color: #999;

  .limitTxt,
  .uploading {
    position: absolute;
    bottom: 10%;
    left: 0;
    width: 100%;
    font-size: 14px;
    text-align: center;
  }
}

// 拖拽
.vue-draggable {
  display: flex;
  flex-wrap: wrap;
/deep/ li {
    width: 146px;;
}
  .draggable-item {
    margin-right: 5px;
    margin-bottom: 5px;
    border: 1px solid #ddd;
    border-radius: 6px;
    position: relative;
    overflow: hidden;

    .el-image {
      width: 100%;
      height: 100%;
    }
    .status-label {
      position: absolute;
      right: -15px;
      top: -6px;
      width: 40px;
      height: 24px;
      background: #13ce66;
      text-align: center;
      transform: rotate(45deg);
      z-index: 1;
      & .status-upload-success {
        color: #fff;
        line-height: 24px;
        transform: rotate(-45deg);
        left: 15px;
        top: 6px;
        position: absolute;
        font-size: 10px;
      }
    }
    .shadow {
      width: 100%;
      height: 100%;
      position: absolute;
      top: 0;
      right: 0;
      background-color: rgba(0,0,0,.5);
      opacity: 0;
      transition: opacity .3s;
      color: #fff;
      font-size: 20px;
      line-height: 20px;
      padding: 2px;
    }
    &:hover {
      .shadow {
        opacity: 1;
      }
    }
    & .shadow-icon {
      margin: 0;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      cursor: pointer;
    }
  }
  &.hideShadow {
    .shadow {
      display: none;
    }
  }
  &.single {
    overflow: hidden;
    position: relative;

    .draggable-item {
      position: absolute;
      left: 0;
      top: 0;
      z-index: 1;
    }
  }
  &.maxHidden {
    .uploadBox {
      display: none;
    }
  }
}
// el-image
.el-image-viewer__wrapper {
  .el-image-viewer__mask {
    opacity: .8;
  }
  .el-icon-circle-close {
    color: #fff;
  }
}
</style>

 

posted @ 2023-09-26 10:18  lyf遠方  阅读(61)  评论(0)    收藏  举报