基于elementplus封装的多图上传并可拖拽排序组件

准备工作

npm install sortablejs //拖拽组件
npm install element-plus //element组件库

1、子组件内

HTML部分

<div class="dragTable d-flex flex-warp" ref="dragTable" style="position: relative">
    <div class="cropper" v-for="(item,index) in imgList" >
      <img :src="item.imageName" width="90" class="avatar mr-10" height="90"/>
      <div @click.stop class="imageUrlHover d-flex just-around align-center px-20">
        <el-icon @click="handleBig(item)" size="20" class="cursor-pointer">
          <ZoomIn/>
        </el-icon>
        <el-icon @click="handleRemove(index)" size="20" class="cursor-pointer ml-10">
          <Delete/>
        </el-icon>
      </div>
    </div>
    <el-upload
      ref="uploadRef"
      v-if="!isMove"
      readonly
      :file-list="fileList"
      class="avatar-uploader mr-10"
      style="width: 90px;height: 90px;"
      accept=".jpg,.png,.jpeg,.webp"
      :show-file-list="false"
      :on-change="beforUpload"
      :multiple="true"
      :auto-upload="false"
      :on-exceed="handleExceed"
      drag
      :limit="10"
    >
      <el-icon style="width: 88px;height: 88px;" class="avatar-uploader-icon">
        <Plus class=" "/>
      </el-icon>
    </el-upload>
  </div>
  <el-dialog width="600px" :title="dialogTitle" v-model="imgVisible">
    <img w-full width="560" :src="imageUrl" alt="Preview Image"/>
  </el-dialog>
</div>

script部分

import {defineEmits, nextTick, ref} from "vue";
import {ElMessage, UploadProps} from "element-plus";
import {uploadFile} from "@/api/user";//此处是你上传文件的方法
import Sortable from "sortablejs";
import {blobToFile} from "@/utils/common";//此方法在文末
import {Delete, ZoomIn,Plus} from '@element-plus/icons-vue'

const imgVisible = ref(false);
const imageUrl = ref(null);
const dialogTitle = ref('');
//查看大图
const handleBig = (e:any) => {
  imgVisible.value = true;
  imageUrl.value = e.imageName;
  dialogTitle.value = '查看图片';
}

const fileList = ref([]);
const imgList:any = ref([]);
let coverImageIndex = 1;
const beforUpload: UploadProps["beforeUpload"] = async (rawFile:any) => {
  if (rawFile.status !== 'ready') return;
  try {
    //此处转换是因为我接口所需要的参数是这个格式 具体的得看你们接口需要传什么类型的数据
    let file = {
      file:blobToFile(rawFile.raw, rawFile.name)
    }
    initDropTable();
    await handleSuccess(file)
  } catch (error:any) {
    // 处理错误
    ElMessage.error(error);
    fileList.value = [];
    imgList.value = [];
  }
}
const emit = defineEmits(['setImgList'])
const handleSuccess = async (file: any) => {
  let e = await uploadFile(file);
  if (e.code === 200) {
    imgList.value.push({
      sn: coverImageIndex++,
      imageName: e.data.objectName
    })
    emit('setImgList',imgList.value)
  }
}
const handleRemove = (index:any) => {
  imgList.value.splice(index,1);
}

const handleExceed = (files:any, fileList:any)=>{
  // files为当前选择的文件,fileList已经选择后的文件(上次选择的)
  //提示最多只能上传10个
  if(fileList.length + files.length>10){
    ElMessage.error('最多上传10个文件!');
    return
  }
}

const dragTable = ref();
const isMove = ref(false);//拖拽开始时隐藏上传按钮 以防他也被拖动位置
const initDropTable = () => {
  if(dragTable.value){
    const el = dragTable.value;
    Sortable.create(el, {
      handle:'.cropper',
      animation: 150,
      ghostClass: 'blue-background-class',
      onStart:()=>{
        isMove.value = true;
      },
      onEnd: ({ newIndex , oldIndex }) => {
        isMove.value = false;
        const arr = imgList.value;
        if(newIndex == arr.length){
          return
        }
        const currRow = arr.splice(oldIndex, 1)[0];
        arr.splice(newIndex, 0, currRow);
        imgList.value = [];
        nextTick(() => {
          imgList.value = arr;
        })
      }
    })
  }
}
</script>

2、父组件内

HTML部分

<upload-img-drag @setImgList="setDetailsImgList"></upload-img-drag>

script部分

import UploadImgDrag from "@/components/uploadImgDrag.vue";
const setDetailsImgList = (e:any) => {
  formState.detailsImgList = e;
}

3、SCSS部分

.cropper{
  position: relative;
  .imageUrlHover {
      display: none;
      position: absolute;
      width: 90px;
      height: calc(100% - 10px);
      z-index: 10;
      color: white;
      left: 0;
      border-radius: 5px;
      top: 0;
      background-color: rgb(0, 0, 0, 0.5);
  }
}
.avatar{
  border-radius: 5px;
  height: auto;
}
.avatar:hover + .imageUrlHover {
  display: flex;
  transition: all 0.5s;
}

.imageUrlHover:hover {
display: flex;
}

4、blobToFile转换方法

export const blobToFile = (blob: any, fileName: string) => {
    return new window.File([blob], fileName, {
        type: blob.type,
    });
};

5、效果图

在这里插入图片描述

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值