原生js 实现拖拽排序
本文实现了一个基于HTML5拖拽API的可排序列表功能。通过设置元素的draggable属性,结合dragstart、dragenter和dragend事件处理,实现了列表项的拖拽排序效果。关键点包括:使用getElementsByClassName获取动态元素集合,通过异步方式设置拖拽样式,利用flex布局实现纵向排列,以及正确处理拖拽过程中的元素索引变化。CSS部分设置了user-select
·
实现效果

代码详情
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="list">
<!-- draggable 属性必须设置,因为css设置了user-select为none -->
<div draggable="true" class="list-item">1</div>
<div draggable="true" class="list-item">2</div>
<div draggable="true" class="list-item">3</div>
<div draggable="true" class="list-item">4</div>
<div draggable="true" class="list-item">5</div>
<div draggable="true" class="list-item">6</div>
</div>
</body>
</html>
<script>
// 拖拽排序
const list = document.querySelector('.list');
const listItems = document.getElementsByClassName('list-item'); // 获取所有列表项 不要用 querySelectorAll因为它返回的是静态的NodeList,而getElementsByClassName返回的是动态的HTMLCollection
let dragItem = null;
let dragIndex = null; // 拖拽的元素索引
let enterIndex = null; // 进入的元素索引
list.addEventListener('dragstart', (e) => {
setTimeout(() => {
// 改成异步的,必须鼠标跟随的样式也变成move的样式
e.target.classList.add('move');
dragItem = e.target;
}, 0);
});
list.addEventListener('dragenter', (e) => {
e.preventDefault(); // 阻止默认行为 dragenter ,否则放开鼠标时可能会有问题
if(e.target === list || e.target === dragItem) return; // 如果拖拽的元素是列表本身或者拖拽的元素本身,则不执行后续操作
// const listItems = [...list.children] // 如果不在外部声明listItems 在这个时候必须重新获取listItems 因为listItems的顺序是动态变化的
dragIndex = Array.from(listItems).indexOf(dragItem); // 拖拽的元素索引
enterIndex = Array.from(listItems).indexOf(e.target); // 进入的元素索引
if(enterIndex < dragIndex) {
// 往上排
console.log('向上排')
list.insertBefore(dragItem, e.target);
} else {
// 往下排
console.log('向下排')
list.insertBefore(dragItem, e.target.nextSibling);
}
});
list.addEventListener('dragend', (e) => {
e.target.classList.remove('move');
dragItem = null;
dragIndex = null;
enterIndex = null;
})
</script>
<style>
.list {
display: flex;
/* flex-direction 上下排列 */
flex-direction: column;
gap: 10px;
}
.list-item {
padding: 10px;
background-color: #f0f0f0;
cursor: grab;
user-select: none; /* 防止拖拽时选中文字 但会导致默认的drag失效 */
}
.list-item.move {
/* 被选中拖拽时的样式 */
background: transparent;
color: transparent;
border: 1px dashed #ccc;
}
</style>
代码知识要点
- querySelectorAll它返回的是静态的NodeList,而getElementsByClassName返回的是动态的
如果list-item的顺序被改变了,querySelectorAll 不会是最新的list-item - css设置了user-select为none 是防止拖拽时选中文字 但会导致默认的drag失效,所以为了drag能正常实现,list-item必须设置属性 draggable 为true
- dragstart 内使用异步的方式为被选中拖拽的盒子增加move样式,是为了防止,跟随鼠标的样式也变成了move的样式
- flex布局 只要改变 flex-direction 就可以将上下排列拖拽,变为横向的排列拖拽
更多推荐


所有评论(0)