产品:上传图片拖拽一下怎么了 ?

前戏

一、需求背景:一个产品经理的执念 📌

"小X啊,这个商品详情页的图片要能拖动排序,就像手机相册那样丝滑!"

------ 来自产品经理的第7次需求变更

作为前端炒粉,面对这个"简单"需求时,我望着Element Plus官方文档陷入了沉思 🤔。el-upload组件虽然能完美处理上传,但原生并不支持已上传图片的拖拽排序。于是,当然是选择满足他啦...

一、需求背景

言归歪传,在管理后台开发中,经常需要实现图片上传与排序功能。Element Plus的el-upload组件虽然提供了基础的图片上传功能,但原生并不支持已上传图片的拖拽排序。下面将基于el-upload组件,结合HTML5拖放API,实现图片上传后的拖拽排序的基本功能。


二、实现效果

  1. 上传后的图片支持拖拽交换位置
  2. 实时预览拖拽后的排序效果

三、核心实现分析:魔法背后的秘密 🧙

1. 模板结构解析🛠️

html 复制代码
<el-upload
  list-type="picture-card"
  :auto-upload="false"
  :limit="10"
  v-model:file-list="userInfo.pictureMobile"
  :on-change="handleChange"
>
  
  <!-- 自定义文件项模板 -->
  <template #file="{ file }">
    <div
      draggable="true"          <!-- 开启拖拽功能 -->
      @dragstart="handleDragStart($event,file,'mb')"
      @drop="handleDrop($event,file,'mb')"
      @dragover.prevent>        <!-- 阻止默认行为 -->
      <img :src="file.url" />
      <!-- 操作按钮 -->
      <span class="el-upload-list__item-actions">
        <span @click="handlePictureCardPreview(file)">
          <el-icon><zoom-in /></el-icon>
        </span>
        <span @click="handleRemove(file,'mb')">
          <el-icon><Delete /></el-icon>
        </span>
      </span>
    </div>
  </template>
</el-upload>

2. 逻辑实现🎨

拖拽二部曲 📦→📦

🎯第一步:拖拽开始事件处理:dragstart

  • 获取当前拖拽项的索引
  • 将索引存入数据传输对象
typescript 复制代码
const handleDragStart = (event, file, type: string) => {
  // 图片列表
  const imgList = userInfo.picturePc;
  
  const index = imgList.findIndex(element => element === file);

  event.dataTransfer.setData('index', index.toString());
}

🎯第二步:拖拽释放事件处理:handleDrop

  • 获取目标位置索引
  • 阻止默认行为
  • 获取拖拽源索引
  • 创建数组副本(保证响应式更新)
  • 执行数组元素移动
  • 更新图片列表
typescript 复制代码
const handleDrop = (event, file, type) => {
  // 获取目标位置索引
  const index = imgList.findIndex(element => element === file);
  
  // 阻止默认行为
  event.preventDefault();

  // 获取拖拽源索引
  const draggedIndex = Number(event.dataTransfer.getData('index'));
  
  // 创建数组副本(保证响应式更新)
  const updatedList = [...imgList];
  
  // 执行数组元素移动
  const [draggedItem] = updatedList.splice(draggedIndex, 1);
  updatedList.splice(index, 0, draggedItem);

  // 更新对应类型的图片列表
    userInfo.picturePc = updatedList
}

四、关键点

1. HTML5拖放API

  • draggable="true":使元素可拖拽
  • @dragstart:拖拽开始时触发
  • @drop:拖拽释放时触发
  • @dragover.prevent:阻止默认拖拽行为
  • dataTransfer:跨事件数据传输对象

2. 数组操作技巧

typescript 复制代码
// 删除并插入元素的经典写法
const updatedList = [...originalList];
const [movedItem] = updatedList.splice(oldIndex, 1);
updatedList.splice(newIndex, 0, movedItem);

3. 响应式更新

通过创建数组副本并重新赋值,触发Vue的响应式更新:

typescript 复制代码
userInfo.pictureMobile = updatedList

五、踩坑日记:程序员的自我修养 📖

🚧 坑1:幽灵图片问题

现象 :拖拽时出现半透明残影
解法:给拖拽元素添加CSS样式

css 复制代码
.dragging-item {
  opacity: 0.5;
  transform: rotate(3deg);
}

🚧 坑2:移动端兼容性

现象 :手机滑动触发页面滚动
解法:添加touch-action样式

css 复制代码
.mobile-container {
  touch-action: none;
}

六、完整实现流程

  1. 🎯 初始化el-upload组件,禁用自动上传
  2. ✨ 通过file-list绑定图片数据源
  3. 🔮 自定义文件项模板,添加拖拽事件
  4. ⚡ 实现拖拽开始时的索引记录
  5. 🌈 处理拖拽释放时的元素交换)
  6. 🧪更新响应式数据触发视图刷新

七、总结

通过结合el-upload的文件管理能力和HTML5原生拖放API,简单实现了直观的图片拖拽排序功能。

这种方案具有以下优势:

优势 说明
轻量级 无需额外依赖库
高兼容 基于原生API实现
易扩展 支持多场景类型参数

下次再见!🌈

相关推荐
福兮说7 小时前
设计稿是 #4A7C6F,页面量出来是 #4B7C6F:HEX、HSL、透明度、canvas 来回转的七个坑
前端·javascript·css·canvas
郑州光合科技余经理8 小时前
海外版外卖加盟:总站与分站配送规则怎么分开管
java·开发语言·前端·后端·uni-app·php·ai编程
专业程序开发源8 小时前
springboot简历管理系统81389-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·spring·php·课程设计
专业程序开发源8 小时前
springboot社区养老系统44071-计算机课程设计、毕业设计
vue.js·spring boot·后端·python·django·php·课程设计
小呆呆6668 小时前
副业搞起来,小说,漫画,漫剧的成本优化思路
前端·后端·面试
凤城老人9 小时前
从 PyQt6 到 Electron:给 Edge TTS 做一个“多角色配音机“的踩坑手记
javascript·typescript·electron
Dovis(誓平步青云)9 小时前
浇水提醒刚弹出又消失,植物状态别只存一个百分比
开发语言·前端·javascript·pdf·ecmascript·电脑
码艺-Alimjan9 小时前
Vben Admin 新增维吾尔语 Vben-Modal的关键坑之一
前端·javascript·vue.js
可乐鸡翅yeah_10 小时前
hls.js 手动自定义 http 请求 loader,修改请求头实战
开发语言·前端·javascript·网络协议·http·ecmascript·m3u8在线
IT_陈寒10 小时前
Vite静态资源导入这个坑我帮你们踩过了
前端·人工智能·后端