vue基于element封装上传图片,拖拽

基于elementPlus封装上传图片,可延伸上传文件等,基础代码记录,具体上传事件未处理,此处个人记录保存一下,可拖拽改变顺序

第一种

<template>
  <div class="img-upload-layout">
    
    <!-- 文件列表 -->
    <transition-group class="img-upload-list" name="el-fade-in-linear" tag="ul">
      <li 
        class="img-upload-list__item img-upload-list__img"
        v-for="(file, index) in fileLists" 
        :key="file.uid" 
        @dragstart="handleDragStart($event,file,index)" 
        @dragenter="handleDragEnter($event,file,index)" 
        @dragover.prevent="handleDragOver($event,file,index)" 
        @dragend="handleDragEnd($event, file,index)" 
        :draggable="true"
      >
        <el-image
          style="width: 120px; height: 120px"
          :src="file.url"
          :preview-src-list="[file.url]"
          fit="contain"
        />
        <div class="operation-item-wrap">
          <span class="item-delete operation-item" @click="handleRemove(file,index)" >
            <el-icon><Delete /></el-icon>
          </span>
        </div>
      </li>
      <li class="img-upload-list__item img-upload-list__btn">
        <el-upload
          ref="imgUploadRef"
          class="upload-img-uploader"
          list-type="picture-card"
          accept="image/*"
          :show-file-list="false"
          :auto-upload="false"
          :multiple="props.multiple"
          :action="uploadFileUrl"
          :headers="headers"
          :file-list="fileLists"
          :limit="props.limit"
          :on-exceed="handleExceed"
          :on-change="handleUploadChange"
          :before-upload="handleBeforeUpload"
          :on-success="handleUploadSuccess"
          :on-error="handleUploadError"
        >
          <!-- 上传按钮 -->
          <el-icon ><Plus /></el-icon>
        </el-upload>
      </li>
    </transition-group>
  </div>
</template>

<script setup>

const props = defineProps({
  modelValue: [String, Object, Array],
  // 上传按钮文字
  btnText: {
    type: String,
    default: '选取文件',
  },
  // 数量限制
  limit: {
    type: Number,
    default: 300,
  },
  multiple: {
    type: Boolean,
    default: true,
  },
  // 大小限制(MB)
  fileSize: {
    type: Number,
    default: 5,
  },
});

const { proxy } = getCurrentInstance();
const emit = defineEmits();

const imgUploadRef = ref(null)
const uploadFileUrl = ref(import.meta.env.VITE_APP_BASE_API + "/file/upload"); 
const uploadFileUrlAuth = ref(import.meta.env.VITE_APP_BASE_API + "/system/uploadPrivate"); 
// 上传header传参
const headers = ref({ Authorization: "Bearer eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjoiYWI2ODE0ZjItMGExZC00MzEzLTllM2UtMDBlYjQ2YjJiOGFiIiwidXNlcl9rZXkiOiI5ZTEyNThjMS03NzFjLTQ1NWItYWYxNy03YzcwNzVjZmU5ZWMiLCJ1c2VybmFtZSI6InN6YWRtaW4ifQ.z3gy7ogoZU80Qdp2oOHOl6ZTSWmfbTUpC_NPBphVCTkj9Grku8Q0QcN0R_VS3OWLuopsXqsZ1129bb5v7Wqzqg" });
const fileLists = ref([]);
const uploadList = ref([]);

// 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
const handleUploadChange = (file,files) => {
  // status = 'ready' | 'uploading' | 'success' | 'fail'
  fileLists.value.push(file)
  console.log(fileLists.value,'=========handleUploadChange=====',files,file);
}
// 上传前校检 
const handleBeforeUpload = (file) => {
  console.log('=========handleBeforeUpload=====',file);
  // // 校检文件大小
  // if (props.fileSize) {
  //   const isLt = file.size / 1024 / 1024 < props.fileSize;
  //   if (!isLt) {
  //     proxy.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
  //     return false;
  //   }
  // }
  return true;
};
// 上传成功回调
const handleUploadSuccess = (res, file) => {
  console.log(res,'=======================handleUploadSuccess=======================',file);
  if(res && res.code == 200){
    uploadList.value.push(file);
    if (uploadList.value.length === number.value) {
      fileLists.value = fileLists.value.filter(f => f.fileUrl !== undefined).concat(uploadList.value);
      uploadList.value = [];
      number.value = 0;
      emit("update:modelValue", fileLists.value );
    }
  }else{
    proxy.$modal.msgError(res && res.msg ? res.msg : '上传文件失败');
  }
  
};
// 上传失败
const handleUploadError = (err) => {
  console.log('=======================handleUploadError=======================',err);
  proxy.$modal.msgError("上传文件失败");
};
// 文件个数超出
const handleExceed = () => {
  console.log('=======================handleExceed=======================');
  proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
};
const handleRemove = (file,index) => {
  fileLists.value.splice(index, 1);

  // fileLists.value = fileLists.value.filter(item => item.uid != file.uid)
  console.log(fileLists.value,'=======================handleRemove=======================',file);
};
const handlePreview = (file) => {
  console.log('=======================handlePreview=======================',file);
};
// 拖动事件处理
const draggingItem = ref(null)
const draggingIdx = ref(-1)
const handleDragStart = (e,item,index) => {
  console.log(e,item,'============================handleDragStart======================', index);
  draggingItem.value = item
  draggingIdx.value = index
};
// 首先把元素变成可以放置的元素,即重写dragenter/dragover
const handleDragEnter = (e,item,index) => {
  console.log(e,item,'============================handleDragEnter======================', index);
  e.preventDefault();
  if (draggingItem.value && item.uid == draggingItem.value.uid) {
    return;
  }
  const newListItems = [...fileLists.value];
  const indexOfFlag = newListItems.indexOf(draggingItem.value);
  const dst = newListItems.indexOf(item);
  newListItems.splice(dst, 0, ...newListItems.splice(indexOfFlag, 1));
  fileLists.value = JSON.parse(JSON.stringify(newListItems));
};
const handleDragOver = (e,item,index) => {
  console.log(e,item,'============================handleDragOver======================', index);
  e.preventDefault();
};
const handleDragEnd = (e,item,index) => {
  console.log(e,item,'============================handleDragEnd======================', index);
  draggingItem.value = null
  draggingIdx.value = -1
};

</script>

<style lang="scss">
.img-upload-layout{
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;
  .upload-img-uploader{
    .el-upload--picture-card{
      width: 120px;
      height: 120px;
    }
  }
  .img-upload-list{
    display: flex;
    justify-content: flex-start;
    align-items: flex-start;
    flex-wrap: wrap;
    &__item{
      width: 120px;
      height: 120px;
      &:hover{
        .operation-item-wrap{
          display: flex;
        }
      }
    }
    &__img{
      border: 1px solid #e5e5e5;
      border-radius: 8px;
      overflow: hidden;
      margin: 0 6px 12px 6px !important;
      position: relative;
    }
    .operation-item-wrap{
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      width: 100%;
      height: 24px;
      background-color: rgb(0 0 0 / 40%);
      padding: 0 4px;
      box-sizing: border-box;
      display: flex;
      justify-content: flex-end;
      display: none;
      .el-icon{
        font-size: 20px;
        color: #ffffff;
      }
      .operation-item{
        cursor: pointer;
        margin-right: 4px;
        display: flex;
        align-items: center;
        justify-content: center;
        &:hover{
          opacity: .85;
        }
      }
    }
  }
}
</style>

第二种

<template>
  <div class="img-upload-layout">
    <div class="draggable-img-btn">
      <el-upload
        ref="imgUploadRef"
        class="upload-img-uploader"
        list-type="picture-card"
        accept="image/*"
        :show-file-list="false"
        :auto-upload="false"
        :multiple="props.multiple"
        :action="uploadFileUrl"
        :headers="headers"
        :file-list="fileLists"
        :limit="props.limit"
        :on-exceed="handleExceed"
        :on-change="handleUploadChange"
        :before-upload="handleBeforeUpload"
        :on-success="handleUploadSuccess"
        :on-error="handleUploadError"
      >
        <!-- 上传按钮 -->
        <el-icon ><Plus /></el-icon>
        <template #tip>
          <div class="el-upload__tip">
            请选择大小在{{props.fileSize}}M内的图片
          </div>
        </template>
      </el-upload>
    </div>
    <!-- 文件列表 -->
    <draggable
      class="draggable-img-group"
      tag="draggable-img-group" 
      item-key="uid" 
      v-model="fileLists"
      :component-data="{name:'fade'}" 
      @change="handleDragChange" 
      @update="handleDragUpdate" 
      @end="handleDragEnd" 
    >
      <template #item="{element,index}">
        <div class="draggable-img-group__item">
          <el-image
            style="width: 120px; height: 120px"
            :src="element.url"
            :preview-src-list="[element.url]"
            fit="contain"
          />
          <div class="operation-item-wrap">
            <span class="item-delete operation-item" @click="handleRemove(element,index)" >
              <el-icon><Delete /></el-icon>
            </span>
          </div>
        </div>
        
      </template>
    </draggable>  
    
  </div>
</template>

<script setup>
import draggable from 'vuedraggable'

const props = defineProps({
  modelValue: [String, Object, Array],
  // 上传按钮文字
  btnText: {
    type: String,
    default: '选取文件',
  },
  // 数量限制
  limit: {
    type: Number,
    default: 300,
  },
  multiple: {
    type: Boolean,
    default: true,
  },
  // 大小限制(MB)
  fileSize: {
    type: Number,
    default: 5,
  },
});

const { proxy } = getCurrentInstance();
const emit = defineEmits();

const imgUploadRef = ref(null)
const uploadFileUrl = ref(import.meta.env.VITE_APP_BASE_API + "/file/upload"); 
const uploadFileUrlAuth = ref(import.meta.env.VITE_APP_BASE_API + "/system/uploadPrivate"); 
// 上传header传参
const headers = ref({ Authorization: "Bearer eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjoiYWI2ODE0ZjItMGExZC00MzEzLTllM2UtMDBlYjQ2YjJiOGFiIiwidXNlcl9rZXkiOiI5ZTEyNThjMS03NzFjLTQ1NWItYWYxNy03YzcwNzVjZmU5ZWMiLCJ1c2VybmFtZSI6InN6YWRtaW4ifQ.z3gy7ogoZU80Qdp2oOHOl6ZTSWmfbTUpC_NPBphVCTkj9Grku8Q0QcN0R_VS3OWLuopsXqsZ1129bb5v7Wqzqg" });
const fileLists = ref([]);
const uploadList = ref([]);

// 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
const handleUploadChange = (file,files) => {
  // status = 'ready' | 'uploading' | 'success' | 'fail'
  fileLists.value.push(file)
  console.log(fileLists.value,'=========handleUploadChange=====',files,file);
}
// 上传前校检 
const handleBeforeUpload = (file) => {
  console.log('=========handleBeforeUpload=====',file);
  // // 校检文件大小
  if (props.fileSize) {
    const isLt = file.size / 1024 / 1024 < props.fileSize;
    if (!isLt) {
      proxy.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
      return false;
    }
  }
  return true;
};
// 上传成功回调
const handleUploadSuccess = (res, file) => {
  console.log(res,'=======================handleUploadSuccess=======================',file);
  if(res && res.code == 200){
    uploadList.value.push(file);
    if (uploadList.value.length === number.value) {
      fileLists.value = fileLists.value.filter(f => f.fileUrl !== undefined).concat(uploadList.value);
      uploadList.value = [];
      number.value = 0;
      emit("update:modelValue", fileLists.value );
    }
  }else{
    proxy.$modal.msgError(res && res.msg ? res.msg : '上传文件失败');
  }
  
};
// 上传失败
const handleUploadError = (err) => {
  console.log('=======================handleUploadError=======================',err);
  proxy.$modal.msgError("上传文件失败");
};
// 文件个数超出
const handleExceed = () => {
  console.log('=======================handleExceed=======================');
  proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
};
const handleRemove = (file,index) => {
  fileLists.value.splice(index, 1);
  console.log(fileLists.value,index,'=======================handleRemove=======================',file);
};

const handleDragEnd = (e) => {
  console.log(fileLists.value,'==============handleDragEnd===============',e);
};

 
</script>

<style lang="scss">
.img-upload-layout{
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;
  flex-direction: column;
  .draggable-img-btn{
  }
  .upload-img-uploader{
    .el-upload--picture-card{
      width: 56px;
      height: 56px;
    }
  }
  .draggable-img-group{
    display: flex;
    justify-content: flex-start;
    align-items: flex-start;
    flex-wrap: wrap;
    &__item{
      width: 120px;
      height: 120px;
      border: 1px solid #e5e5e5;
      border-radius: 8px;
      overflow: hidden;
      margin: 0 6px 12px 6px !important;
      position: relative;
      &:hover{
        .operation-item-wrap{
          display: flex;
        }
      }
      .operation-item-wrap{
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        width: 100%;
        height: 24px;
        background-color: rgb(0 0 0 / 40%);
        padding: 0 4px;
        box-sizing: border-box;
        display: flex;
        justify-content: flex-end;
        display: none;
        .el-icon{
          font-size: 20px;
          color: #ffffff;
        }
        .operation-item{
          cursor: pointer;
          margin-right: 4px;
          display: flex;
          align-items: center;
          justify-content: center;
          &:hover{
            opacity: .85;
          }
        }
      }
    }
  }
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/570186.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器学习模型效果不好及其解决办法

当训练出来的机器学习模型效果不佳时&#xff0c;可能涉及多个方面的原因。为了改善模型的效果&#xff0c;需要系统地检查和分析问题的根源&#xff0c;并采取相应的措施进行优化。 一、数据问题 数据质量 检查数据是否干净、完整&#xff0c;是否存在噪声、异常值或缺失值。…

OCP Java17 SE Developers 复习题13

答案 D, F. There is no such class within the Java API called ParallelStream, so options A and E are incorrect. The method defined in the Stream class to create a parallel stream from an existing stream is parallel(); therefore, option F is correct, and o…

2024年区块链链游即将迎来大爆发

随着区块链技术的不断发展和成熟&#xff0c;其应用领域也在不断扩展。其中&#xff0c;区块链链游&#xff08;Blockchain Games&#xff09;作为区块链技术在游戏行业中的应用&#xff0c;备受关注。2024年&#xff0c;区块链链游行业即将迎来爆发&#xff0c;这一趋势不容忽…

4款黑科技软件,其中三款功能过于强大,被误认为是外国佬开发的

国人对国产软件的刻板印象往往是“捆绑安装、弹窗广告、高昂收费”&#xff0c;这使得许多优秀的国产软件如同明珠蒙尘&#xff0c;鲜为人知。甚至有些软件的功能之强大&#xff0c;以至于常被人们误以为是出自外国佬开发&#xff0c;这实在是令人遗憾的事情。 1、VeryCapture…

docker快速搭建部署mqtt

文章目录 前言一、mqtt是什么&#xff1f;二、使用步骤1.引入库2.创建临时容器3.创建挂在目录4.将临时容器的配置挂载到宿主机中5.删除临时容器6.运行容器并挂载文件7.登录EMQX内置的管理控制台 总结 前言 一、mqtt是什么&#xff1f; MQTT&#xff08;Message Queuing Teleme…

内容+货架“攻防一体”,京东能否上演“后来居上”?

又一家货架电商出手了。 2023年底&#xff0c;阿里进一步融合内容电商板块&#xff0c;合并淘宝直播与逛逛成立内容电商事业部&#xff0c;推动内容电商进入了新的阶段。近日&#xff0c;京东也开始发力视频赛道&#xff0c;宣布将拿出10亿现金、10亿流量补贴&#xff0c;全力…

C语言-结构体尺寸

CPU字长 字长的概念指的是处理器在一条指令中的数据处理能力&#xff0c;当然这个能力还需要搭配操作系统的设定&#xff0c;比如常见的32位系统、64位系统&#xff0c;指的是在此系统环境下&#xff0c;处理器一次存储处理的数据可以达32位或64位。 地址对齐 当计算机系统的…

Day 32 122.买卖股票的最佳时机II 55. 跳跃游戏 45.跳跃游戏II

买卖股票的最佳时期Ⅱ 给定一个数组&#xff0c;它的第 i 个元素是一支给定股票第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易&#xff08;多次买卖一支股票&#xff09;。 注意&#xff1a;你不能同时参与多笔交易&#xff08;你…

RAKsmart洛杉矶大带宽服务器支持哪些操作系统?

RAKsmart洛杉矶大带宽服务器支持多种操作系统。具体包括以下几种&#xff0c;rak部落小编为您整理发布RAKsmart洛杉矶大带宽服务器支持哪些操作系统? RAKsmart作为一家提供海外服务器租用服务的公司&#xff0c;其洛杉矶大带宽服务器支持安装和运行多种操作系统。 这些操作系统…

WebServer项目介绍文章【四叶专属】

Linux项目实战C轻量级Web服务器源码分析TinyWebServer 书接上文&#xff0c;学习开源项目的笔记没想到居然有不少阅读量&#xff0c;后面结合另一个前端开源项目简单做了点修改&#xff0c;没想到居然有需要的同学&#xff0c;那么我就专门为四叶开一篇文章吧&#xff0c;【源码…

探索区块链世界:赋能创新,揭示区块链媒体发稿的影响力-世媒讯

区块链&#xff0c;这个由“区块”和“链”组成的概念&#xff0c;可能在您眼中充满神秘和复杂&#xff0c;但其实甚至无所不在&#xff0c;它正静悄悄地改变着我们日常生活的方方面面&#xff0c;从金融到媒体&#xff0c;从医疗到教育。 我们来揭开区块链的神秘面纱。区块链…

前端零代码开发实践:页面嵌套+逻辑连线0开发扩展组件,实现切换开关控制扇叶转动。能无代码封装扩展组件,有别于常规的web组态或低代码平台

前言&#xff1a; 官网:http://www.uiotos.net/ 什么是 UIOTOS&#xff1f; 这是一款拥有独创专利技术的前端零代码工具&#xff0c;专注于解决前端界面开发定制难题&#xff0c;原型即应用&#xff01;具有页面嵌套、属性继承、节点连线等全新特性&#xff0c;学习门槛低…

AI 智能工具以及热门AI开源项目整理,包含国内中科院版GPT

AI 智能工具以及热门AI开源项目整理&#xff0c;包含国内中科院版GPT。 不用xx即可访问的镜像网站 https://chat1.yqcloud.top https://chat.bnu120.space https://chat.aidutu.cn https://hzdjs.cn/chatgpt https://chats.fenqubiao.com/zh 需要xx才能访问的网站 https://o…

金融时报:波场亮相哈佛大学并举办TRON Builder Tour活动

近日,波场TRON作为顶级白金赞助商出席哈佛区块链会议并成功举办TRON Builder Tour哈佛站活动,引发海外媒体热议。美联社、金融时报、Cointelegraph等国际主流媒体及加密知名媒体均对此给予了高度评价,认为本次大会对TRON Builder Tour活动具有里程碑意义,彰显了波场TRON致力于促…

spring security登录认证授权

spring security登录认证授权 是什么 Spring Security 主要实现了Authentication&#xff08;认证&#xff0c;解决who are you? &#xff09; 和 Access Control&#xff08;访问控制&#xff0c;也就是what are you allowed to do&#xff1f;&#xff0c;也称为Authorizat…

HTTP与SOCKS-哪种协议更适合您的代理需求?

网络代理技术是我们日常使用网络时必不可少的一项技术&#xff0c;它可以为我们提供隐私保护和负载均衡的能力&#xff0c;从而保证我们的网络通信更加安全和顺畅。而其中最主流的两种协议就是HTTP和SOCKS。虽然它们都是用于网络代理的协议&#xff0c;但在实际应用中却存在着一…

Java | Leetcode Java题解之第45题跳跃游戏II

题目&#xff1a; 题解&#xff1a; class Solution {public int jump(int[] nums) {int length nums.length;int end 0;int maxPosition 0; int steps 0;for (int i 0; i < length - 1; i) {maxPosition Math.max(maxPosition, i nums[i]); if (i end) {end maxP…

【网络安全】XSS漏洞注入,分类,防御方法

1.什么是XSS XSS全称&#xff08;Cross Site Scripting&#xff09;跨站脚本攻击&#xff0c;是最常见的Web应用程序安全漏洞之一&#xff0c;仅次于SQL注入。XSS是指攻击者在网页中嵌入客户端脚本&#xff0c;通常是JavaScript编写的危险代码&#xff0c;当用户使用浏览器浏览…

Linux——NFS网络文件系统

在生产环境中共享宿主目录可以用于集中管理账户 一、存储设备 DAS 是直连存储相当于移动硬盘 NAS 是网络文件系统&#xff0c;挂载后可以直接访问 SAN 存储区域网络 IPSAN 网线连接 共享的是设备&#xff0c;需要挂载后分区使用 FCSAN 光纤连接 二、服务的管理 1、安…

数据结构练习-线性表定义与基本操作

----------------------------------------------------------------------------------------------------------------------------- 1. 线性表是( )。 A.一个有限序列&#xff0c;可以为空 B. 一个有限序列&#xff0c;不可以为空 C. 一个无限序列&#xff0c;可以为空…
最新文章