html+js实现一个简单的列表拖拽排序
最近手头上没有什么事,于是我在空闲的时候,写了一个拖拽排序,虽然市面上现在拖拽排序的库也不少,不过还是自己也要了解一下怎么实现。我采取的是最简单粗暴的方式,直接对数组进行了重组,然后渲染,以达到排序的效果。
不过目前因为时间原因,动画效果还没有添加,后面有时间会更新这篇文章,把动画效果加上。
定义一个几个需要排序的元素
这里我们先生成一个数组,页面拖拽元素由数组遍历得到,其中必须要有一个唯一标识,我这里使用id进行标记,方便后续从list查找,如下:
<template>
<ul id="sortable">
<li :draggable="col.canDrag" v-for="col in list" :id="col.id" :key="col.id">
{{ col.label }}
</li>
</ul>
</template>
<script setup>
const list = ref([
{ canDrag: "true", label: "Col1", id: "col_1" },
{ canDrag: "true", label: "Col2", id: "col_2" },
{ canDrag: "true", label: "Col3", id: "col_3" },
{ canDrag: "true", label: "Col4", id: "col_4" },
]);
</sctipt>
监听拖拽事件
我们元素已经定义好了,在元素拖拽的时候,我们需要添加监听事件,来监听鼠标按下,拖拽,松开的事件,其中主要用到的是按下的事件和松开的事件。在添加监听事件之前,我们需要获取所有的元素块,监听每一个元素,如下:
- 鼠标按下:获取移动的元素;
- 鼠标松开:获取元素堆放的位置;
onMounted(() => {
const sortableItems = document.querySelectorAll(
'#sortable [draggable="true"]'
);
sortableItems.forEach((item) => {
item.addEventListener("dragstart", dragStart); // 获取拖拽的元素
item.addEventListener("dragover", (e) => e.preventDefault());
item.addEventListener("drop", drop); // 获取拖放的位置
});
});
排序处理
我们在上一步添加了监听事件,那么我们来简单介绍一下鼠标事件的时候干了什么吧!
- dragStart:我们获取到当前需要拖拽的元素,并将唯一标识id,放在拖拽的事件中,方便鼠标松开事件中抓取。
- drop:我们先定义一个数组来存储当前的排序序列,然后从拖拽的事件中获取我们拖拽元素的id,并从当前排序序列中抓取移动的元素。再从松开事件获取鼠标需要移动到的id与移动到的位置。
具体代码如下:
function dragStart(event) {
event.dataTransfer.setData("eleId", event.target.id);
}
function drop(event) {
let listTemp = [...(list.value || [])];
event.preventDefault();
const eleId = event.dataTransfer.getData("eleId"); // 移动的id
const moveCol = listTemp.find((o) => o.id === eleId); // 移动的元素
const insertIndex = listTemp.findIndex((o) => o.id === event.target.id); // 鼠标松开的位置
listTemp = listTemp.filter((o) => o.id !== eleId); // 过滤掉移动的元素
listTemp.splice(insertIndex, 0, moveCol); // 在拖放的位置插入移动元素
list.value = listTemp;
}
结语
本文只是采取了一种最简单的方法实现,性能方面可能并没有想象中那么好,包括动画效果,感兴趣的小伙伴可以尝试加一下或者讨论一下,我也会后续时间允许的情况下,实现一下动画的效果。
完整代码
<template>
<ul id="sortable">
<li :draggable="col.canDrag" v-for="col in list" :id="col.id" :key="col.id">
{{ col.label }}
</li>
</ul>
</template>
<script setup>
import { onMounted, ref } from "vue";
let list = ref([
{ canDrag: "true", label: "Col1", id: "col_1" },
{ canDrag: "true", label: "Col2", id: "col_2" },
{ canDrag: "true", label: "Col3", id: "col_3" },
{ canDrag: "true", label: "Col4", id: "col_4" },
]);
onMounted(() => {
const sortableItems = document.querySelectorAll(
'#sortable [draggable="true"]'
);
sortableItems.forEach((item) => {
item.addEventListener("dragstart", dragStart); // 获取拖拽的元素
item.addEventListener("dragover", (e) => e.preventDefault());
item.addEventListener("drop", drop); // 获取拖放的位置
});
});
function dragStart(event) {
event.dataTransfer.setData("eleId", event.target.id);
}
function drop(event) {
let listTemp = [...(list.value || [])];
event.preventDefault();
const eleId = event.dataTransfer.getData("eleId"); // 移动的id
const moveCol = listTemp.find((o) => o.id === eleId); // 移动的元素
const insertIndex = listTemp.findIndex((o) => o.id === event.target.id); // 鼠标松开的位置
listTemp = listTemp.filter((o) => o.id !== eleId); // 过滤掉移动的元素
listTemp.splice(insertIndex, 0, moveCol); // 在拖放的位置插入移动元素
list.value = listTemp;
}
</script>
<style scoped lang="less">
#sortable {
list-style-type: none;
padding: 0;
margin: 0;
cursor: move;
}
#sortable li {
margin: 5px;
padding: 5px;
background-color: #f9f9f9;
border: 1px solid #ddd;
}
</style>
转载自:https://juejin.cn/post/7356506122357047308