前端拖拽排序实现

1. 使用 HTML5

事件

触发时机

核心任务

@dragstart

开始拖拽时

准备数据,贴上标签

@dragover

经过目标上方时

必须 preventDefault(),发出“允许放置”的信号

@dragleave

离开目标上方时

清理高亮等临时视觉效果

@drop

在目标上松手时

接收数据,执行最终逻辑

@dragend

整个拖拽结束时

最终清理,重置所有状态

<template><div class="sortable-list-container"><h3>待办事项 (原生 HTML5 拖拽排序)</h3><ul class="task-list"><!-- 每个 li 既是可拖拽项,也是其他项的放置目标。因此,它需要同时监听 drag 和 drop 相关的事件。--><li v-for="(task, index) in tasks" :key="task.id" class="task-item":class="{ 'drag-over-highlight': draggingOverIndex === index }" draggable="true" @dragstart="onDragStart(index)"@dragover.prevent="onDragOver(index)" @dragleave="onDragLeave" @drop="onDrop(index)" @dragend="onDragEnd">{{ task.name }}</li></ul><div class="raw-data"><h4>实时数据顺序:</h4><pre>{{ tasks }}</pre></div></div>
</template><script setup>import { ref } from 'vue';// 初始数据const tasks = ref([{ id: 1, name: '学习原生拖拽 API' },{ id: 2, name: '编写 onDragStart' },{ id: 3, name: '处理 dragover.prevent' },{ id: 4, name: '实现 onDrop 逻辑' },]);// --- 状态变量 ---// 记录当前正在被拖拽的元素的索引const draggingIndex = ref(null);// 记录当前鼠标悬停在其上方的放置目标的索引const draggingOverIndex = ref(null);// --- 事件处理函数 ---/*** 拖拽开始时触发* @param {number} index - 被拖拽的 task 的索引*/function onDragStart(index) {draggingIndex.value = index;console.log(`开始拖拽: 索引 ${index} - ${tasks.value[index].name}`);// 注意:原生 API 不像库那样有好看的 ghost 效果,// 浏览器会自动创建一个半透明的快照。}/*** 当拖拽元素经过其他元素上方时持续触发* @param {number} index - 当前经过的元素的索引*/function onDragOver(index) {// event.preventDefault() 已经在模板中通过 .prevent 修饰符处理了// 更新悬停目标的索引,用于高亮显示draggingOverIndex.value = index;}/*** 当拖拽元素离开一个放置目标时触发*/function onDragLeave() {// 清除高亮效果draggingOverIndex.value = null;}/*** 在一个放置目标上松开鼠标时触发* @param {number} dropIndex - 松手时所在的元素的索引*/function onDrop(dropIndex) {console.log(`放置到: 索引 ${dropIndex}`);// --- 核心排序逻辑 ---if (draggingIndex.value === null || draggingIndex.value === dropIndex) {// 如果没有拖拽项或放在了原位,则什么都不做return;}// 1. 从数组中“剪切”出被拖拽的元素const movedItem = tasks.value.splice(draggingIndex.value, 1)[0];// 2. 将被拖拽的元素“粘贴”到新的位置tasks.value.splice(dropIndex, 0, movedItem);console.log('数组已重新排序');}/*** 拖拽结束时(成功或失败)触发*/function onDragEnd() {console.log('拖拽结束');// 清理所有状态变量draggingIndex.value = null;draggingOverIndex.value = null;}
</script><style scoped>.task-list {list-style-type: none;padding: 0;width: 300px;border: 1px solid #ccc;border-radius: 4px;}.task-item {padding: 12px;margin: 5px;background-color: #f0f0f0;border: 1px solid #ddd;cursor: grab;transition: all 0.2s ease;}.task-item:active {cursor: grabbing;}/* 当有元素被拖拽到某个 li 上方时,给这个 li 添加高亮效果 */.drag-over-highlight {background-color: #c8ebfb;border-top: 2px solid #3498db;transform: scale(1.02);}.raw-data {margin-top: 20px;font-family: monospace;}
</style>

2. 使用sortable.js

核心难点:谁来掌握 DOM

  • Vue:数据驱动视图,只有 DOM 是唯一主宰。改动 DOM 时会跟据虚拟 DOM 修改真实的 DOM。
  • Sortable:是一个 DOM 操作库,直接移动 DOM 节点实现拖拽效果,对 Vue 的虚拟 DOM 一无所知

如果让它们各干各的,就会乱了。当 SortableJS 移动了 DOM 后,Vue 的数据还是旧的。下一次 Vue 因为任何原因需要重新渲染时,它会看着自己的旧数据,会觉得是出错了,然后,它会强制把 DOM 修正回原始的顺序,导致你拖拽的元素“闪”回原位。

直接把 DOM 操作权给 Sortable

思路:onMounted 使用 sortableJS 把数据通过 new Sortable 传递进去,调用 onEnd 函数,把被拖动的数据直接删除 const movedItem = tasks.value.splice(oldIndex, 1)[0];,然后再将它插入到新的地方 tasks.value.splice(newIndex, 0, movedItem);,在 onUnmounted 中销毁 Sortable 实例防止内存泄漏。

# 下载依赖
npm install sortablejs
<template><div class="sortable-list-container"><h3>待办事项 (由 SortableJS 直接驱动)</h3><p>安装 SortableJS:npm install sortablejs</p><p>如果在使用 TypeScript,最好也安装它的类型定义文件:npm install @types/sortablejs -D</p><!-- 1. 准备一个容器,并用 ref 标记它 --><!-- Vue 会将这个 <ul> 元素赋值给 listRef --><ul ref="listRef" class="task-list"><!-- 2. 正常使用 v-for 渲染列表 --><!-- data-id 属性是可选的,但对于 SortableJS 来说是一个好习惯 --><li v-for="task in tasks" :key="task.id" :data-id="task.id" class="task-item">{{ task.name }}</li></ul><div class="raw-data"><h4>实时数据顺序:</h4><pre>{{ tasks }}</pre></div></div>
</template><script setup>import { ref, onMounted, onUnmounted } from 'vue';// 3. 导入 SortableJSimport Sortable from 'sortablejs';// 初始数据const tasks = ref([{ id: 1, name: '学习 Vue 拖拽' },{ id: 2, name: '编写 Demo' },{ id: 3, name: '提交代码' },{ id: 4, name: '喝杯咖啡' },]);// 创建一个模板引用,用于获取 DOM 元素const listRef = ref(null);// 用于存放 Sortable 实例,方便后续销毁let sortableInstance = null;// 4. 在 onMounted 钩子中初始化 SortableJS// 必须在这里,因为要确保 DOM 元素已经渲染完成onMounted(() => {if (listRef.value) {// 实例化 SortablesortableInstance = new Sortable(listRef.value, {animation: 150, // 拖拽归位时的动画时长,单位 msghostClass: 'ghost', // 拖拽时占位元素的类名// 5. 监听 onEnd 事件,这是“握手”的关键onEnd: (event) => {const { oldIndex, newIndex } = event;console.log(`元素从索引 ${oldIndex} 移动到了 ${newIndex}`);// --- 核心逻辑:更新 Vue 的数据数组 ---// 1. 从数组中移除被拖拽的元素const movedItem = tasks.value.splice(oldIndex, 1)[0];// 2. 将被拖拽的元素插入到新的位置tasks.value.splice(newIndex, 0, movedItem);// ------------------------------------console.log('Vue 的数据数组已同步更新!');},});}});// 6. 在 onUnmounted 钩子中销毁 Sortable 实例// 这是一个好习惯,可以防止内存泄漏onUnmounted(() => {if (sortableInstance) {sortableInstance.destroy();}});
</script><style scoped>.task-list {list-style-type: none;padding: 0;width: 300px;}.task-item {padding: 10px;margin: 5px 0;background-color: #f0f0f0;border: 1px solid #ddd;cursor: move;}/* 拖拽占位符的样式 */.ghost {opacity: 0.5;background: #c8ebfb;}.raw-data {margin-top: 20px;font-family: monospace;}
</style>

3. 使用vue-draggable

这个官网有很多示例,可以参考一下

https://vue-draggable-plus.netlify.app/

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

arm coresight

这是一个arm设计的调试基础架构&#xff0c;我们常用的debug基本都包含在内。比如ETM、PTM、ITM、HTM、ETB等。 注意ETM、PTM、ITM、HTM、ETB是coresight的子集。这些工具相比普通debug的断点调试&#xff0c;需要更高的专业水平&#xff0c;因此也用于复杂软件故障定位、性能…

《华为基本法》 —— 企业发展的导航仪

当一家企业从 “小作坊” 向 “规模化组织” 跨越时&#xff0c;最需要的是什么&#xff1f;华为的答案&#xff0c;藏在 1998 年出台的《华为基本法》里。1998 年&#xff0c;《华为基本法》正式颁布&#xff0c;这部凝结华为早期经营智慧的纲领性文件&#xff0c;不仅为华为从…

【完整源码+数据集+部署教程】传统韩文化元素分割系统: yolov8-seg-GFPN

背景意义 研究背景与意义 随着全球化的加速&#xff0c;传统文化的保护与传承面临着前所未有的挑战。尤其是韩国的传统文化&#xff0c;作为东亚文化的重要组成部分&#xff0c;蕴含着丰富的历史、艺术和哲学内涵。然而&#xff0c;随着现代化进程的推进&#xff0c;许多传统文…

构建AI智能体:三十五、决策树的核心机制(一):刨根问底鸢尾花分类中的参数推理计算

一、初识决策树想象一个生活中的场景&#xff0c;我们去水果店买一个西瓜&#xff0c;该怎么判断一个西瓜是不是又甜又好的呢&#xff1f;我们可能会问自己一系列问题&#xff1a;首先看看它的纹路清晰吗&#xff1f;如果“是”&#xff0c;那么它可能是个好瓜。如果“否“&…

c语言中实现线程同步的操作

线程 常见问题 同步权限 在多线程 / 多进程并发时&#xff0c;为避免共享资源&#xff08;如内存变量、硬件设备、文件&#xff09;被同时修改导致的数据不一致&#xff0c;需要通过 “同步机制” 控制谁能访问资源 ——“获取同步权限” 就是线程 / 进程申请这种访问资格的过程…

一台设备管理多个 GitHub 账号:从配置到切换的完整指南

一台设备管理多个 GitHub 账号&#xff1a;从配置到切换的完整指南 在日常开发中&#xff0c;我们经常需要在同一台电脑上使用多个 GitHub 账号&#xff08;比如个人账号和工作账号&#xff09;。但默认情况下&#xff0c;Git 会优先使用全局配置的账号&#xff0c;导致推送代…

即插即用,秒入虚拟:TouchDIVER Pro 触觉手套 赋能 AR/VR 高效交互

一、即插即用&#xff0c;零门槛开启沉浸之旅 在XR&#xff08;扩展现实&#xff09;技术高速发展的今天&#xff0c;用户对“真实感”的追求愈发迫切。Weart公司旗下旗舰产品TouchDIVER Pro触觉手套&#xff0c;凭借无需适配器、无需复杂设置的极简设计&#xff0c;打破传统触…

GitHub热榜项目 - 日榜之应用场景与未来发展趋势

一、引言GitHub热榜项目 - 日榜呈现出丰富多样的技术成果&#xff0c;这些项目蕴含着巨大的应用潜力&#xff0c;并且对未来数智化技术的发展有着重要的指示作用。深入探究其应用场景以及未来发展趋势&#xff0c;能让我们更好地把握技术发展方向&#xff0c;将这些前沿技术应用…

Linux网络:socket编程TCP

文章目录前言一&#xff0c;服务器端流程1-1 绑定协议1-2 绑定IP和端口1-3 监听客户端1-4 接收连接1-5 收发数据1-6 关闭连接1-7 服务端整体代码二&#xff0c;客户端流程2-1 指定地址和端口2-2 连接服务器2-3 发送消息2-4 客户端整体代码前言 TCP 的通信过程就像两个人打电话…

飞书智能查询机器人搭建说明文档

飞书智能查询机器人搭建说明文档 一、使用手册 1. 创建飞书机器人应用 如果仅需对接已有机器人应用则可跳过该步骤&#xff08;建议各业务部门独立使用各自的机器人应用&#xff09;。在飞书开发者后台中创建企业自建应用&#xff0c;添加机器人应用能力并申请对应的身份权限…

蓝色系列包装行业网站 适合企业站,带手机版自适应

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 蓝色通用企业网站是基于SDCMS四合一企业网站管理系统开发的模板&#xff0c;适合企业站&#xff0c;带手机版。 四网合一企业网站管理系统是一个以PHPMySQL/Sqlite进行开发的四网合一网…

【大模型:知识图谱】--6.Neo4j DeskTop安装+使用

上一期讲了图知识库的安装&#xff0c; 【图数据库】--Neo4j 安装_neo4j安装-CSDN博客 现在来看看可视化管理程序&#xff1a;Neo4j DeskTop的安装. 需要先安装java环境&#xff0c;具体看上面 目录 1.Neo4j DeskTop版下载 2.Neo4j DeskTop版安装 3.Neo4j DeskTop版使用 …

Python爬虫实战——使用NetNut网页解锁器获取亚马逊电商数据

文章目录一、电商数据的作用1.1 支撑科学决策&#xff0c;降低试错成本1.2 提升运营效率&#xff0c;实现降本增效1.3 深化用户理解&#xff0c;驱动个性化服务1.4 监测竞品动态&#xff0c;制定差异化策略1.5 驱动产品创新&#xff0c;满足用户需求二、爬取目标三、环境准备四…

超越NAT:如何构建高效、安全的内网穿透隧道

在敏捷开发和分布式协作成为主流的今天&#xff0c;开发者需要一个能够将本地开发环境瞬间暴露给公网的能力&#xff0c;以便进行演示、联调或处理回调。传统方案如配置路由器端口映射或部署VPN&#xff0c;不仅繁琐且存在安全风险。内网穿透技术&#xff0c;特别是以 ngrok、Z…

第二十三章 ESP32S3 RTC 实验

本章介绍 ESP32-S3 实时时钟&#xff08;RTC&#xff09;的使用&#xff0c;实时时钟能为系统提供一个准确的时间&#xff0c;即时系统复位或主电源断电&#xff0c; RTC 依然能够运行&#xff0c;因此 RTC 也经常用于各种低功耗场景。通过本章的学习&#xff0c;将学习到 RTC …

Java 轻松实现 Markdown 转 Word、PDF、HTML

在软件开发和技术写作领域&#xff0c;Markdown 已成为一种被广泛使用的轻量级标记语言。它的语法简洁&#xff0c;书写效率高&#xff0c;非常适合快速记录笔记、撰写技术文档或博客文章。但在实际应用中&#xff0c;Markdown 文件往往需要被转换为更通用的格式&#xff0c;例…

Kafka系列之:Kafka broker does not support the ‘MetadataRequest_v0‘ Kafka protocol.

Kafka系列之:Kafka broker does not support the MetadataRequest_v0 Kafka protocol. 一、完整报错 二、错误原因 三、解决方法 一、完整报错 kafka.errors.IncompatibleBrokerVersion: IncompatibleBrokerVersion: Kafka broker does not support the ‘MetadataRequest_v0’…

开源AI红队工具“Red AI Range“助力发现、分析与缓解AI系统漏洞

开源AI红队平台Red AI Range&#xff08;RAR&#xff09;正在改变安全专业人员评估和强化AI系统的方式。该平台通过模拟真实攻击场景&#xff0c;利用容器化架构和自动化工具&#xff0c;简化了AI特有漏洞的发现、分析和缓解流程。**核心功能** 1. 武器库/目标按钮可快速启动…

SQL 数据库简介

SQL&#xff08;Structured Query Language&#xff09;是一种用于管理和操作关系型数据库的标准语言。关系型数据库以表格形式存储数据&#xff0c;并通过行和列的结构化方式组织信息。SQL 提供了一套强大的命令&#xff0c;用于查询、插入、更新和删除数据&#xff0c;以及管…

SpringBoot4与Spring7发布:云原生深度进化

Spring Boot 4和Spring Framework 7带来基础要求升级、模块化改进、API版本化、声明式HTTP客户端、弹性注解等重大特性&#xff0c;标志着Java开发生态向云原生时代的深度进化。 近日&#xff0c;Spring生态迎来了自2022年以来最具里程碑意义的更新——Spring Boot 4和Spring …