原生JS實現(xiàn)拖拽排序的示例代碼
說到拖拽,應用場景不可謂不多。無論是打開電腦還是手機,第一眼望去的界面都是可拖拽的,靠拖拽實現(xiàn)APP或者應用的重新布局,或者拖拽文件進行操作文件。
先看效果圖,如何實現(xiàn)一個如圖HTML元素的拖拽并排序

HTML中的拖拽事件(drag & drop)
參考MDN中文文檔
事件類型
- drag : 當拖拽的元素或者選中的文本時觸發(fā)
- dragend : 當拖拽元素結束時觸發(fā)
- dragenter : 當拖拽元素或選中的文本到一個可釋放目標時觸發(fā)
- dragleave : 當拖拽元素或選中的文本離開一個可釋放目標時觸發(fā)
- dragover : 當元素或選中的文本被拖到一個可釋放目標上時觸發(fā)(每 100 毫秒觸發(fā)一次)
- dragstart : 當用戶開始拖拽一個元素或選中的文本時觸發(fā)
- drop : 當元素或選中的文本在可釋放目標上被釋放時觸發(fā)
Coding
寫一段簡單的CSS和html ,實現(xiàn)初始的頁面
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul{
margin: 200px auto;
width: 200px;
list-style-type: none;
}
li{
margin: 5px;
text-align: center;
width: 200px;
height: 30px;
background: skyblue;
}
.list .moving{
background: transparent;
color: transparent;
border: 1px dashed #ccc;
}
<ul class="list">
<li >1</li>
<li >2</li>
<li >3</li>
<li >4</li>
<li >5</li>
</ul>
此時我們的頁面如下圖

現(xiàn)在還不可以進行拖拽操作,為了可以實現(xiàn)拖拽操作,我們必須給每個元素設置 draggable="true"
<ul class="list">
<li draggable="true">1</li>
<li draggable="true">2</li>
<li draggable="true">3</li>
<li draggable="true">4</li>
<li draggable="true">5</li>
</ul>元素已經(jīng)可以基礎的拖拽

接下來我們需要在JS中對DOM元素進行一系列操作來實現(xiàn)對應的效果
- 實現(xiàn)拖出去的元素,原位置樣式變?yōu)橥该魈摼€
- 實現(xiàn)拖動到其他元素上時,列表順序發(fā)生改變
let list = document.querySelector('.list')
let currentLi // 記錄拖拽元素
我們用事件委托,監(jiān)聽 "dragstart" 事件,給拖動的元素添加類名,修改樣式,這里會出現(xiàn)奇怪的一幕就是,拖動的樣式和原來的樣式同時變成了透明。
list.addEventListener('dragstart',(e)=>{
e.dataTransfer.effectAllowed = 'move' // 拖動樣式改為 "move"
currentLi = e.target
currentLi.classList.add('moving')
})這里會出現(xiàn)奇怪的一幕就是,拖動的樣式和原來的樣式同時變成了透明。這是因為跟隨鼠標拖動的元素的樣式在拖動的那一刻是原始元素的樣式,所以也會添加"moving", 那么在這里我們加一個異步

list.addEventListener('dragstart',(e)=>{
e.dataTransfer.effectAllowed = 'move'
currentLi = e.target
setTimeout(()=>{
currentLi.classList.add('moving')
})
})
到這里距離目標又更近了一步,
接下來我們需要在拖動的過程中對列表的元素進行重新的排序
Node.insertBefore():方法在參考節(jié)點之前插入一個擁有指定父節(jié)點的子節(jié)點
list.addEventListener('dragenter',(e)=>{
e.preventDefault() // 阻止默認事件
if(e.target === currentLi||e.target === list){ // 當移動到當前拖動元素,或者父元素上面我們不做操作
return
}
let liArray = Array.from(list.childNodes)
let currentIndex = liArray.indexOf(currentLi) // 獲取到拖動元素的下標
let targetindex = liArray.indexOf(e.target) // 獲取到目標元素的下標
if(currentIndex<targetindex){
list.insertBefore(currentLi,e.target.nextElementSibling)
}else{
list.insertBefore(currentLi,e.target)
}
})最后我們需要在拖拽結束將元素的moving類名移除,以及阻止拖拽到一個目標上的默認事件(否則會出現(xiàn)禁止)
list.addEventListener('dragover',(e)=>{
e.preventDefault()
})
list.addEventListener('dragend',(e)=>{
currentLi.classList.remove('moving')
})至此,一個簡單的拖拽排序功能就實現(xiàn)了

完整代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul{
margin: 200px auto;
width: 200px;
list-style-type: none;
}
li{
margin: 5px;
text-align: center;
width: 200px;
height: 30px;
background: skyblue;
}
.list .moving{
background: transparent;
color: transparent;
border: 1px dashed #ccc;
}
</style>
</head>
<body>
<ul class="list">
<li draggable="true">1</li>
<li draggable="true">2</li>
<li draggable="true">3</li>
<li draggable="true">4</li>
<li draggable="true">5</li>
</ul>
<script>
let list = document.querySelector('.list')
let currentLi
list.addEventListener('dragstart',(e)=>{
e.dataTransfer.effectAllowed = 'move'
currentLi = e.target
setTimeout(()=>{
currentLi.classList.add('moving')
})
})
list.addEventListener('dragenter',(e)=>{
e.preventDefault()
if(e.target === currentLi||e.target === list){
return
}
let liArray = Array.from(list.childNodes)
let currentIndex = liArray.indexOf(currentLi)
let targetindex = liArray.indexOf(e.target)
if(currentIndex<targetindex){
list.insertBefore(currentLi,e.target.nextElementSibling)
}else{
list.insertBefore(currentLi,e.target)
}
})
list.addEventListener('dragover',(e)=>{
e.preventDefault()
})
list.addEventListener('dragend',(e)=>{
currentLi.classList.remove('moving')
})
</script>
</body>
</html>以上就是原生JS實現(xiàn)拖拽排序的示例代碼的詳細內(nèi)容,更多關于JS拖拽排序的資料請關注腳本之家其它相關文章!
相關文章
基于layui數(shù)據(jù)表格以及傳數(shù)據(jù)的方式
今天小編就為大家分享一篇基于layui數(shù)據(jù)表格以及傳數(shù)據(jù)的方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08
JS 控制小數(shù)位數(shù)的實現(xiàn)代碼
上網(wǎng)查一查的確存在這種Bug,除了位數(shù)上控制之外也沒什么也好的方法(希望高手能提出其它思路)。2011-08-08
動態(tài)加載iframe時get請求傳遞中文參數(shù)亂碼解決方法
這篇文章主要介紹了動態(tài)加載iframe時get請求傳遞中文參數(shù)亂碼解決方法,需要的朋友可以參考下2014-05-05
chorme 瀏覽器記住密碼后input黃色背景處理方法(兩種)
使用chrome瀏覽器選擇記住密碼的賬號,輸入框會自動加上黃色的背景,有些設計輸入框是透明背景的,需要去除掉這個黃色的背景。下面給大家分享chorme 瀏覽器記住密碼后input黃色背景處理方法,一起看看吧2017-11-11

