前端拖拽排序實現

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
英文地址,請注明出處:http://en.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 …