html+js实现一个简单的列表拖拽排序

最近手头上没有什么事,于是我在空闲的时候,写了一个拖拽排序,虽然市面上现在拖拽排序的库也不少,不过还是自己也要了解一下怎么实现。我采取的是最简单粗暴的方式,直接对数组进行了重组,然后渲染,以达到排序的效果。

不过目前因为时间原因,动画效果还没有添加,后面有时间会更新这篇文章,把动画效果加上。

定义一个几个需要排序的元素

这里我们先生成一个数组,页面拖拽元素由数组遍历得到,其中必须要有一个唯一标识,我这里使用id进行标记,方便后续从list查找,如下:

html 复制代码
<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>

监听拖拽事件

我们元素已经定义好了,在元素拖拽的时候,我们需要添加监听事件,来监听鼠标按下,拖拽,松开的事件,其中主要用到的是按下的事件和松开的事件。在添加监听事件之前,我们需要获取所有的元素块,监听每一个元素,如下:

  • 鼠标按下:获取移动的元素;
  • 鼠标松开:获取元素堆放的位置;
js 复制代码
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与移动到的位置。

具体代码如下:

js 复制代码
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;
}

结语

本文只是采取了一种最简单的方法实现,性能方面可能并没有想象中那么好,包括动画效果,感兴趣的小伙伴可以尝试加一下或者讨论一下,我也会后续时间允许的情况下,实现一下动画的效果。

完整代码

html 复制代码
<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>
相关推荐
艾小码6 分钟前
这份超全JavaScript函数指南让你从小白变大神
前端·javascript
reembarkation15 分钟前
vue 右键菜单的实现
前端·javascript·vue.js
00后程序员张2 小时前
Fiddler抓包工具使用教程,代理设置与调试方法实战解析(含配置技巧)
前端·测试工具·ios·小程序·fiddler·uni-app·webview
gplitems1236 小时前
Consua WordPress Theme — Business Consulting Sites That Convert With Clarity
javascript
雾削木7 小时前
stm32解锁芯片
javascript·stm32·单片机·嵌入式硬件·gitee
2301_768350238 小时前
Vue第二期:组件及组件化和组件的生命周期
前端·javascript·vue.js
小周同学:8 小时前
Vue项目中将界面转换为PDF并导出的实现方案
javascript·vue.js·pdf
华洛9 小时前
公开一个AI产品的商业逻辑与设计方案——AI带来的涂色卡自由
前端·后端·产品
明远湖之鱼9 小时前
opentype.js 使用与文字渲染
前端·svg·字体
90后的晨仔10 小时前
Vue 3 组合式函数(Composables)全面解析:从原理到实战
前端·vue.js