前端拖拽排序实现详解:从原理到实践 - 附完整代码

前端拖拽排序实现详解:从原理到实践 - 附完整代码
在这里插入图片描述
🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志
🎐 个人CSND主页——Micro麦可乐的博客
🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战
🌺《RabbitMQ》专栏19年编写主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战
🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解
🌛《开源项目》本专栏主要介绍目前热门的开源项目,带大家快速了解并轻松上手使用
🍎 《前端技术》专栏以实战为主介绍日常开发中前端应用的一些功能以及技巧,均附有完整的代码示例
✨《开发技巧》本专栏包含了各种系统的设计原理以及注意事项,并分享一些日常开发的功能小技巧
💕《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程
🌞《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整
👍《Spring Security》专栏中我们将逐步深入Spring Security的各个技术细节,带你从入门到精通,全面掌握这一安全技术
如果文章能够给大家带来一定的帮助!欢迎关注、评论互动~

前端拖拽排序实现详解:从原理到实践 - 附完整代码

1. 前言

在我们前端开发过程中经常会用到排序的功能,其中列表项的拖拽排序(Drag-and-Drop Sortable)不仅能让用户直观、高效地调整顺序,还能大幅提升交互体验。无论是管理后台的菜单排序、看板(Kanban)中任务卡片的调整,还是移动端的图片/视频重排,拖拽排序都是不可或缺的交互模式。

在这里插入图片描述


本文博主将带着小伙伴从零开始,用原生 HTML5 Drag & Drop API 实现一个简洁的可拖拽排序列表,并模拟向后端提交新顺序的完整流程。


2. 拖拽排序的应用

任务管理工具
用户可以拖拽卡片改变优先级或在不同分组间移动(如Trello

内容管理系统
页面元素排序(如WordPress

图片/视频排序
相册管理、商品轮播图顺序调整

问卷表单选项
管理问答列表时,调整题目或选项顺序更直观

自定义导航菜单
后台可视化拖拽菜单层级与顺序

这些场景下,通过拖拽排序,用户无需点上下箭头、输入序号,就能快速完成调整,显著提升效率与体验。


3. 核心实现原理

3.1 HTML5拖放API基础

在这里插入图片描述


HTML5 Drag & Drop 原生 API 核心流程如下:

  • 设定可拖拽元素:draggable="true"
  • 监听拖拽开始:dragstart 事件,记录当前拖拽项索引或标识
  • 允许拖拽进入目标:在目标元素或容器上 dragover 事件中调用 event.preventDefault()
  • 处理放置:drop 事件中获取拖拽项和目标项索引,完成 DOM 位置交换。
  • 结束拖拽:可选的 dragend 事件,用于清理样式或状态。

3.2 关键事件解析

默认拖放API具备以下几个事件类型:

事件类型触发时机常用操作
dragstart开始拖拽元素时设置被拖拽元素的ID
dragenter进入目标元素时添加视觉反馈
dragover在目标元素上悬停时阻止默认行为(允许放置)
dragleave离开目标元素时移除视觉反馈
drop在目标元素上释放时处理元素位置交换
dragend拖拽操作结束时清理状态

4. 完整示例代码

下面是一个最小可运行的示例,小伙伴们可以复制至本地测试运行,注意后端排序保存已经将当前顺序的 ID 数组传递,后端接口小伙伴们自行实现即可

<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><title>拖拽排序示例</title><style>body{font-family: sans-serif;padding: 20px;}#sortable-list{list-style: none;padding: 0;width: 300px;margin: 0 auto;}#sortable-list li{padding: 10px 15px;margin-bottom: 8px;background: #f0f0f0;border: 1px solid #ddd;cursor: move;user-select: none;}/* 拖拽时样式 */.dragging{opacity: 0.5;}.over{border-top: 2px solid #007bff;}</style></head><body><h2>拖拽排序示例</h2><ulid="sortable-list"><lidata-id="1"draggable="true">项目 1</li><lidata-id="2"draggable="true">项目 2</li><lidata-id="3"draggable="true">项目 3</li><lidata-id="4"draggable="true">项目 4</li><lidata-id="5"draggable="true">项目 5</li></ul><buttonid="saveOrderBtn">保存顺序</button><script>const list = document.getElementById('sortable-list');let dragSrcEl =null;functionhandleDragStart(e){ dragSrcEl =this;this.classList.add('dragging'); e.dataTransfer.effectAllowed ='move'; e.dataTransfer.setData('text/plain',this.dataset.id);}functionhandleDragOver(e){ e.preventDefault();// 必须阻止默认,才有 drop 事件 e.dataTransfer.dropEffect ='move';returnfalse;}functionhandleDragEnter(e){if(this!== dragSrcEl){this.classList.add('over');}}functionhandleDragLeave(e){this.classList.remove('over');}functionhandleDrop(e){ e.stopPropagation();// 阻止事件冒泡if(dragSrcEl !==this){// 在 DOM 中交换位置const nodes = Array.from(list.children);const srcIndex = nodes.indexOf(dragSrcEl);const targetIndex = nodes.indexOf(this);if(srcIndex < targetIndex){ list.insertBefore(dragSrcEl,this.nextSibling);}else{ list.insertBefore(dragSrcEl,this);}}returnfalse;}functionhandleDragEnd(e){// 清理样式this.classList.remove('dragging'); Array.from(list.children).forEach(item=>{ item.classList.remove('over');});}// 绑定事件 Array.from(list.children).forEach(item=>{ item.addEventListener('dragstart', handleDragStart); item.addEventListener('dragenter', handleDragEnter); item.addEventListener('dragover', handleDragOver); item.addEventListener('dragleave', handleDragLeave); item.addEventListener('drop', handleDrop); item.addEventListener('dragend', handleDragEnd);});// 模拟后端提交新顺序 document.getElementById('saveOrderBtn').addEventListener('click',()=>{const order = Array.from(list.children).map(li=> li.dataset.id); console.log('新的顺序:', order);// 示例:POST 到 /api/update-orderfetch('/api/update-order',{ method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({ order })}).then(res=>{if(!res.ok)thrownewError('保存失败');return res.json();}).then(data=>{alert('顺序保存成功!');}).catch(err=>{ console.error(err);alert('保存失败,请重试');});});</script></body></html>

要点说明:

1、每个 <li> 元素设置了 draggable="true"data-id 作为唯一标识;
2、dragstart 时记录源元素并设置拖拽数据;
3、dragover 必须 preventDefault(),否则无法触发 drop
4、drop 事件中根据源元素和目标元素在父容器中的索引,动态交换位置;
5、点击“保存顺序”按钮后,将当前顺序的 ID 数组发送给后端接口 /api/update-order,完成持久化。

5. 结语

通过上述示例,相信小伙伴们已经掌握了使用原生 HTML5 Drag & Drop API 实现前端拖拽排序的全流程:从可拖拽元素配置、事件监听,到 DOM 顺序交换,再到模拟后端提交。

该方案无需引入第三方库,也足够轻量易懂。可以根据项目需求进一步优化:

  • 性能优化:对大型列表使用虚拟化或节流拖拽事件。
  • 视觉增强:使用动画(CSS transition)平滑排序过程。
  • 多容器拖拽:扩展至跨列表、跨分组的拖拽。
  • 第三方库:在复杂场景下可结合 SortableJSDragula 等成熟库。

希望本文能帮助小伙伴们快速在项目中落地拖拽排序功能,如果你在实践过程中有任何疑问或更好的扩展思路,欢迎在评论区留言,最后希望大家一键三连给博主一点点鼓励!


Read more

GTC2026前瞻(二)Agentic AI 与开源模型篇+(三)Physical AI 与机器人篇

GTC2026前瞻(二)Agentic AI 与开源模型篇+(三)Physical AI 与机器人篇

(二)Agentic AI 与开源模型篇 Agentic AI与开源模型:英伟达想定义的,不只是“更聪明的模型”,而是“能持续工作的数字劳动力” 如果说过去两年的大模型竞赛,核心问题还是“谁能生成更像人的答案”,那么到了 GTC 2026,问题已经明显变了。英伟达把 Agentic AI 直接列为大会四大核心主题之一,官方对这一主题的定义也很明确:重点不再是单轮问答,而是让 AI agent 能够推理、规划、检索并执行动作,最终把企业数据转化为可投入生产的“数字劳动力”。这说明,Agentic AI 在英伟达的语境里,已经不是一个前沿概念,而是下一阶段 AI 商业化的主战场。(NVIDIA) 一、GTC 2026真正的变化,是 AI 开始从“会回答”走向“会做事”

AI写作避坑指南:用Qwen3-4B-Instruct少走弯路

AI写作避坑指南:用Qwen3-4B-Instruct少走弯路 1. 引言:为何选择Qwen3-4B-Instruct进行AI写作? 在当前生成式AI快速发展的背景下,越来越多的内容创作者、开发者和研究者开始借助大语言模型提升写作效率。然而,面对参数规模从0.5B到70B不等的各类模型,如何在性能、资源消耗与输出质量之间做出平衡,成为实际应用中的关键挑战。 Qwen3-4B-Instruct 作为阿里云通义千问系列中面向指令理解优化的40亿参数模型,凭借其出色的逻辑推理能力、长文本生成稳定性以及对CPU环境的良好支持,成为高性价比AI写作的理想选择。尤其在集成高级WebUI后,该模型不仅适用于技术文档、小说创作、代码生成等复杂任务,还能在无GPU环境下稳定运行,极大降低了使用门槛。 本文将围绕 “AI 写作大师 - Qwen3-4B-Instruct” 镜像 的实际部署与使用经验,系统梳理常见误区,并提供可落地的优化建议,帮助用户高效利用这一工具,避免踩坑。 2. 模型特性解析:为什么4B是AI写作的“黄金平衡点”? 2.1 参数规模与能力边界 相较于更小的0.5B或

Stable Diffusion 3.5-FP8模型是否支持WebGPU加速?未来可期

Stable Diffusion 3.5-FP8模型是否支持WebGPU加速?未来可期 在一台轻薄本上,用浏览器打开一个网页,输入“赛博朋克风格的机械猫,在雨夜城市中跳跃”——几秒后,一幅细节丰富、光影逼真的4K图像跃然屏上。整个过程无需安装任何软件,不上传数据,也不依赖云端服务器。 这听起来像科幻?其实离我们并不遥远。 随着Stable Diffusion 3.5-FP8这类高性能量化模型的推出,以及WebGPU等新一代Web计算标准的成熟,这样的场景正逐步成为现实。关键问题来了:FP8模型能在WebGPU上跑起来吗? 答案是:目前还不行,但——非常接近了。🚀 🔍 为什么是FP8? 先说清楚一件事:FP8不是简单的“砍精度”。它不像早期的INT8量化那样容易导致生成质量断崖式下降。相反,FP8(尤其是E4M3和E5M2格式)通过精心设计的指数-尾数结构,在仅用1字节存储的情况下,依然保留了足够的动态范围来应对扩散模型中复杂的激活分布。 举个例子,原始SD3.5使用FP16时,显存占用大约9GB,推理时间可能要十几秒;而FP8版本直接压缩到约4.5GB,速度提升40%

AIGC时代的网络安全威胁与应急响应机制构建

AIGC时代的网络安全威胁与应急响应机制构建

文章目录 * 一、AIGC时代的网络安全威胁 * 二、应急响应机制的构建 * 三、代码示例 * 《网络安全应急管理与技术实践》 * 编辑推荐 * 内容简介 * 作者简介 * 目录 * 前言/序言 随着人工智能生成内容(AIGC)技术的迅猛发展,我们正步入一个前所未有的创新与变革的新时代。然而,与这一技术革新相伴的,不仅仅是便利和效率的提升,更有日益严峻的网络安全威胁。AIGC技术在显著提升内容生成效率与质量的同时,也悄然带来了新的攻击面与潜在风险,这些风险若不及时应对,将对个人、组织乃至整个社会造成深远的影响。 一、AIGC时代的网络安全威胁 在AIGC时代,数据泄露与隐私侵犯的风险愈发突出。AIGC技术依赖于海量数据,这些数据中不乏敏感信息,一旦数据保护措施出现疏漏,这些信息就可能被不法分子恶意利用,导致个人隐私泄露、财产损失等严重后果。 此外,恶意代码注入也是AIGC系统面临的一大威胁。在系统的训练或推理过程中,如果输入数据未经严格过滤,就可能被注入恶意代码,进而引发系统瘫痪、数据篡改等安全问题。 算法偏见与歧视同样不容忽视。