最近学到了一个很好玩的东西,拖拽排序,学会了立马来跟大家分享一下,主要使用到的技术是H5新增的draggable
。
draggable
最终效果如下
或者
我们来拆分一下代码,首先把html和css搞定
html部分
<ul class="drag-box">
<li draggable="true" class="drag-item">
<div class="drag-content">
<div class="drag-context">1</div>
</div>
</li>
<li draggable="true" class="drag-item">
<div class="drag-content">
<div class="drag-context">2</div>
</div>
</li>
<li draggable="true" class="drag-item">
<div class="drag-content">
<div class="drag-context">3</div>
</div>
</li>
<li draggable="true" class="drag-item">
<div class="drag-content">4</div>
</li>
<li draggable="true" class="drag-item">
<div class="drag-content">5</div>
</li>
<li draggable="true" class="drag-item">
<div class="drag-content">6</div>
</li>
<!-- <li draggable="true" class="drag-item">
<div class="drag-content">7</div>
</li>
<li draggable="true" class="drag-item">
<div class="drag-content">8</div>
</li>
<li draggable="true" class="drag-item">
<div class="drag-content">9</div>
</li> -->
</ul>
给所有需要进行拖动的元素写上draggable="true"
,允许拖动,注意是写在拖动部分的最外层容器上。css部分就小伙伴们自己来实现吧。
接下来就是js部分,js部分使用拖放的监听事件来完成:
开始拖动(dragstart)
当用户开始拖动一个元素或者一个选择文本的时候
dragstart
事件就会触发。
我们使用最外层的ul节点来代理拖动开始的dragstart
事件
const dragList = document.querySelector(".drag-box"); // 获取拖动区域的容器
let sourceNode = null; // 保存当前拖动的元素
dragList.ondragstart = (e) => {
setTimeout(() => {
e.target.classList.add('moving'); // 拖动开始时加上正在拖动元素的样式
});
sourceNode = e.target;
};
由于在拖动开始时就添加拖动样式,会导致跟随鼠标拖动的元素的样式改变,比如moving样式为
.drag-item.moving {
border: 1px dashed black;
}
所以在这里使用异步来添加moving样式
拖动到目标位置时(dragenter)
当拖动的元素或被选择的文本进入有效的放置目标时,
dragenter
事件被触发。
由于dragenter事件默认取消拖动,如不清除默认事件,则会发现在拖动结束时拖动的元素会闪回原始位置,所以要取消默认事件
dragList.ondragenter = (e) => {
e.preventDefault(); // 清除默认事件
let target = e.target;
if(target === sourceNode || target === dragList) { // 放置目标不是自身元素或者最外层容器时有效
return ;
}
// 由于拖动的元素可能(实际上开发场景肯定会有)包含子元素,所以使用while循环将当前元素锁定在拖动元素的最外层容器上
while(target.parentNode !== dragList) {
target = target.parentNode;
};
const children = Array.from(dragList.children);
const sourceIndex = children.indexOf(sourceNode); // 获取拖动元素的下标
const targetIndex = children.indexOf(target); // 获取目标元素的下标
if(sourceIndex > targetIndex) { // 向上拖动
dragList.insertBefore(sourceNode, target); // 将拖动元素插入目标元素之前
} else { // 向下拖动
// 将拖动元素插入目标元素之后
dragList.insertBefore(sourceNode, children[targetIndex + 1]);
}
};
dragover
也有同样的默认事件,所以对dragover
也要清除默认事件
dragList.ondragover = (e) => {
e.preventDefault();
};
拖动结束(dragend)
dragend
事件在拖放操作结束时触发(通过释放鼠标按钮或单击 escape 键)。
dragList.ondragend = (e) => {
e.target.classList.remove('moving'); // 删除拖动样式
};
至此我们就实现了一个基本的拖拽排序的功能
前端小渣渣的学习总结,如有错误,欢迎指正!!
技术参考:抖音渡一Web前端学习