Vue 3 拖拽排序功能優化實現:從原理到實戰應用

一、引言:為什么需要拖拽排序?

在現代Web應用中,交互體驗越來越受到重視。拖拽排序(Drag and Drop)作為一種直觀的用戶交互方式,被廣泛應用于:

  • 任務管理工具(如Trello的任務卡片排序)

  • 內容管理系統(CMS中的模塊排序)

  • 電商平臺(商品分類排序)

  • 表單構建器(字段順序調整)

  • 多媒體畫廊(圖片/視頻排序)

本文將帶你深入理解Vue 3中實現高效拖拽排序的技術方案,并提供優化后的實現代碼。

二、技術選型對比

1. 原生HTML5拖放API

優點

  • 零依賴,瀏覽器原生支持

  • 性能較好

  • 適合簡單場景

缺點

  • API較為底層

  • 移動端支持有限

  • 自定義樣式困難

2. 第三方庫(如SortableJS、Vue.Draggable)

優點

  • 功能豐富

  • 跨平臺支持好

  • 社區活躍

缺點

  • 包體積增大

  • 自定義程度受限

  • 可能產生不必要的抽象層

3. Vue 3組合式API實現(本文方案)

優勢

  • 完全可控

  • 體積輕量

  • 深度集成Vue響應式系統

  • 易于擴展和定制

三、核心實現原理

1. HTML5拖放事件體系

// 關鍵事件
@dragstart="handleDragStart"  // 拖拽開始
@dragenter="handleDragEnter"  // 進入目標區域
@dragover.prevent            // 在目標區域移動(必須preventDefault)
@dragend="handleDragEnd"     // 拖拽結束

2. Vue響應式數據流

// 使用ref維護狀態
const draggingItemId = ref<string | null>(null)
const targetItemId = ref<string | null>(null)// 計算屬性實現自動排序
const sortedItems = computed(() => {return [...items.value].sort((a, b) => {// 自定義排序邏輯})
})

3. DOM操作優化

// 現代DOM API實現高效元素移動
if (targetIndex > draggingIndex) {targetElement.after(draggingElement) // 向后移動
} else {targetElement.before(draggingElement) // 向前移動
}

四、優化實現代碼

<template><div class="drag-sort-container"><div class="menu-area" ref="listRef" @dragover.prevent><div v-for="item in sortedFruits" :key="item.id" :id="item.id" draggable="true" class="menu-item"@dragstart="handleDragStart($event, item.id)" @dragenter="handleDragEnter($event, item.id)"@dragend="handleDragEnd" :class="{ 'dragging': draggingItemId === item.id }">{{ item.title }}</div></div></div>
</template><script setup lang="ts">
import { ref, computed } from 'vue'interface Fruit {id: stringtitle: string
}const fruits: Fruit[] = [{ id: "1", title: "蘋果" },{ id: "2", title: "香蕉" },{ id: "3", title: "橙子" },{ id: "4", title: "草莓" },{ id: "5", title: "葡萄" }
]const listRef = ref<any>(null)
const draggingItemId = ref<string | null>(null)
const targetItemId = ref<string | null>(null)// 使用計算屬性實現響應式排序
const sortedFruits = computed(() => {// 這里可以根據需要添加排序邏輯return [...fruits]
})const handleDragStart = (event: DragEvent, id: string) => {draggingItemId.value = idevent.dataTransfer?.setData('text/plain', id)event.dataTransfer!.effectAllowed = 'move'// 添加拖動樣式 延時器防止吞掉setTimeout(() => {const target = event.target as HTMLElementtarget.classList.add('dragging')}, 0)
}const handleDragEnter = (event: DragEvent, id: string) => {event.preventDefault()if (!draggingItemId.value || draggingItemId.value === id) returntargetItemId.value = id// 獲取DOM元素const children = [...listRef.value?.children || []]const draggingElement = children.find(el => el.id === draggingItemId.value)const targetElement = children.find(el => el.id === targetItemId.value)if (!draggingElement || !targetElement) return// 交換位置const targetIndex = children.indexOf(targetElement)const draggingIndex = children.indexOf(draggingElement)if (targetIndex > draggingIndex) {targetElement.after(draggingElement)} else {targetElement.before(draggingElement)}
}const handleDragEnd = (event: DragEvent) => {const target = event.target as HTMLElementtarget.classList.remove('dragging')// 更新數據順序const newOrder = [...listRef.value?.children || []].map(el => el.id).filter(id => fruits.some(f => f.id === id))// 這里可以觸發數據更新,例如emit事件或調用APIconsole.log('新順序:', newOrder)// 重置狀態draggingItemId.value = nulltargetItemId.value = null
}
</script><style scoped>
.drag-sort-container {padding: 20px;
}.menu-area {display: flex;flex-wrap: wrap;gap: 10px;border: 1px solid #eee;padding: 10px;min-height: 100px;
}.menu-item {padding: 12px 16px;background-color: #f5f5f5;border-radius: 4px;cursor: move;user-select: none;transition: all 0.3s ease;
}.menu-item:hover {background-color: #e0e0e0;
}.menu-item.dragging {opacity: 0;background-color: #e0e0e0;
}
</style>

本文實現的Vue 3拖拽排序方案具有以下優勢:

  1. 輕量高效:僅依賴Vue 3原生API

  2. 響應式友好:完美融入Vue的響應式系統

  3. 高度可定制:可根據需求擴展功能

未來可能的改進方向:

  • 集成更多動畫效果

  • 實現更復雜的嵌套拖拽場景

希望這篇文章能幫助你構建出體驗優秀的拖拽排序功能!在實際項目中,記得根據具體需求調整實現細節,并做好性能測試。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/93637.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/93637.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/93637.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

git 使用 rebase 刪除某次 提交

git刪除某次commit記錄 在Git中&#xff0c;要刪除某次commit記錄有幾種不同的實現方法&#xff1a; 方法一&#xff1a;使用git rebase命令和~標記 該方法適用于刪除最近的幾次commit記錄。 首先&#xff0c;使用以下命令查看你需要刪除的commit的記錄 git log找到你要刪除的c…

第2章 cmd命令基礎:常用基礎命令(2)

Hi~ 我是李小咖&#xff0c;主要從事網絡安全技術開發和研究。 本文取自《李小咖網安技術庫》&#xff0c;歡迎一起交流學習&#x1fae1;&#xff1a;https://imbyter.com 本節介紹的命令有時間與日期&#xff08;time/date&#xff09;、顯示目錄&#xff08;dir&#xff09;…

我從農村來到了大城市

從田埂到霓虹初到城市那天&#xff0c;行李箱的滾輪碾過柏油路的震動&#xff0c;和老家泥地上的拖沓感完全不同。站在天橋上往下看&#xff0c;車流像被打翻的調色盤&#xff0c;紅的黃的光在柏油畫布上流淌&#xff0c;我數了三遍才認清那是出租車和公交車的尾燈。第一個月總…

代碼隨想錄算法訓練營第三十六天

LeetCode.1049 最后一塊石頭的重量 II 題目鏈接 最后一塊石頭的重量II 題解 class Solution {public int lastStoneWeightII(int[] stones) {int len stones.length;int sum 0;for(int i 0;i<len;i) sum stones[i];int target sum / 2;int[] dp new int[target 1…

Apache Ignite 的監控與指標(Monitoring and Metrics)

這段文檔是關于 Apache Ignite 的監控與指標&#xff08;Monitoring and Metrics&#xff09; 的介紹&#xff0c;內容非常關鍵&#xff0c;尤其在生產環境中保障系統穩定性和性能時至關重要。 我們來一步步深入解析這段文字&#xff0c;幫助你徹底理解其含義和實際意義。&…

【ssh】ubuntu服務器+本地windows主機,使用密鑰對進行ssh鏈接

目錄1、服務器配置ssh2、本地主機秘鑰對3、上傳公鑰至服務器4、配置服務器的公鑰信息5、測試連接1、服務器配置ssh 使用的服務器系統為 ubuntu系統20.04 首先確認服務器是否已安裝SSH&#xff0c;已安裝的話會返回openssh 的相關信息&#xff0c;返回為空表示未安裝 dpkg -l …

Linux文件fd

文件理解 文件屬性內容 打開文件&#xff1a;本質是進程打開文件&#xff0c;文件沒被打開時候再磁盤上。 操作文件&#xff1a;本質是進程操作文件。 在操作系統內部&#xff0c;一定存在大量被打開的文件&#xff0c;會對其進行管理&#xff0c;每一個被打開的文件&#…

北京-4年功能測試2年空窗-報培訓班學測開-第六十四天-準備面試項目(焦慮)-同學開始面試

今日產出&#xff0c;整理自我介紹&#xff0c;繼續整理第一個項目&#xff0c;學習linux命令很焦慮啊很焦慮&#xff0c;很著急今天本打算結束第一個項目的&#xff0c;但是沒能夠&#xff0c;越說感覺越亂&#xff0c;讓同學聽我講&#xff0c;同學說&#xff0c;要聽睡著了于…

網絡是如何運轉的?——常見網絡協議與網絡分層模型

目錄 基本網絡協議 TCP&#xff08;傳輸控制協議&#xff09; 可靠傳輸&#xff1a;序列號確認應答重傳機制 序列號&#xff08;seq&#xff09; 確認應答&#xff08;ACK&#xff09; 超時重傳 三次握手與四次揮手 三次握手&#xff08;建立連接&#xff09; 四次揮手…

OpenAI放大招:ChatGPT學習模式上線,免費AI智能家教

目錄一、背景介紹二、學習模式是什么國內直接使用AI主流模型GPT-5也會第一時間同步更新。三、主要功能特點1、互動式提示2、分層次響應3、個性化支持4、知識檢查5、靈活切換四、學生如何使用學習模式1、訪問方式2、適用場景3、交互過程4、使用示例五、局限性1、依賴學生自覺性2…

設計模式:享元模式 Flyweight

目錄前言問題解決方案享元工廠結構代碼前言 享元是一種結構型設計模式&#xff0c;它摒棄了在每個對象中保存所有數據的方式&#xff0c;通過共享多個對象所共有的相同狀態&#xff0c;讓你能在有限的內存容量中載入更多對象。 問題 假如你希望在長時間工作后放松一下&#x…

Spring Boot容器化實戰:用官方OpenJDK鏡像極速啟動你的應用

前言 用 Docker 打包 Java 應用,尤其是 Spring Boot,簡直是開發者的超級利器。想象一下,你的程序就像勤快的外賣小哥,隨時待命,跑遍任何一臺機器,馬上為你服務。不論是開發環境還是生產環境,Docker 都能讓部署變得輕松又高效,徹底告別“環境不一致”的煩惱。 本篇文章…

【計算機網絡 | 第1篇】計算機網絡概述(上)

文章目錄一.現代通信基礎&#x1f95d;二.網絡、互聯網、英特網&#x1f9fe;1.網絡&#xff08;Network&#xff09;2.互聯網&#xff08;internet&#xff09;3.因特網&#xff08;Internet&#xff09;三.計算機網絡的標準定義&#x1f95d;早期定義&#x1f9fe;物理構成視…

python語法筆記

問題解決辦法 原本是個小問題&#xff0c;但是花了我大量時間。先說最后的解決辦法&#xff1a;360網絡急救箱搞的。一.問題描述 始終拉取失敗 二.解決過程 1.登陸憑證檢測&#xff0c;查下密碼是不是不對。2.清除GIT所有數據 3.使用SSH拉取 生成密鑰網站上添加密鑰SSH 拉取4.G…

XTOM藍光三維掃描儀:解鎖中小尺寸復雜零件的高精度3D檢測新境界

在3C消費電子行業&#xff0c;產品從出廠到用戶手中&#xff0c;可能經歷運輸、使用中的意外跌落。據統計&#xff0c;超過30%的電子產品售后問題與物理沖擊相關。跌落測試可模擬產品在運輸、使用中意外跌落的場景&#xff0c;可評估其結構強度、內部組件抗沖擊能力&#xff0c…

Django+celery異步:拿來即用,可移植性高

一、依賴環境 1、python解釋器版本&#xff1a;python3.7.5 2、穩定依賴包 # Celery 核心 celery5.2.7 kombu5.2.4 billiard3.6.4.0 vine5.0.0# Redis broker backend redis4.3.6# eventlet (如果用 -P eventlet)【windows系統可以使用】 eventlet0.33.3 greenlet1.1.3# 避免…

Ubuntu18.04 LTS +RTL 8125 出現安裝完系統后沒有網絡問題

Ubuntu18.04 LTS RTL 8125 出現安裝完系統后沒有網絡問題問題描述最終解決方案1.下載對應的Realtek網卡驅動&#xff0c;使用命令lspci查看網卡信息安裝網卡3.重啟電腦記錄過程1.內核升級方式1&#xff09;下載新的內核驅動2&#xff09;安裝內核驅動3&#xff09;重啟電腦4&am…

集成電路學習:什么是ARM CortexM處理器核心

ARM Cortex-M是ARM公司專為微控制器( Microcontroller)設計的處理器核心系列,它以其高性能、低功耗和易于開發的特點,在嵌入式系統和微控制器領域得到了廣泛應用。以下是關于ARM Cortex-M的詳細介紹: 一、ARM Cortex-M的概述 ARM Cortex-M系列處理器是基于ARM架構的高能效…

Apache Ignite 的分布式原子類型(Atomic Types)

以下的內容是關于 Apache Ignite 的分布式原子類型&#xff08;Atomic Types&#xff09;&#xff0c;主要包括 IgniteAtomicLong 和 IgniteAtomicReference。它們是 跨集群節點的“全局共享變量”&#xff0c;支持線程安全、原子性操作&#xff0c;即使多個節點同時訪問也能保…

Leetcode 08 java

283. 移動零 提示 給定一個數組 nums&#xff0c;編寫一個函數將所有 0 移動到數組的末尾&#xff0c;同時保持非零元素的相對順序。 請注意 &#xff0c;必須在不復制數組的情況下原地對數組進行操作。 示例 1: 輸入: nums [0,1,0,3,12] 輸出: [1,3,12,0,0] 示例 2: 輸…