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>
相关推荐
mONESY25 分钟前
用 useRef 管理 Worker 线程,让你的页面不再卡顿
javascript
码林鼠3 小时前
2026前端面试题(二)
前端
vx-程序开发4 小时前
django医院预约挂号系统---附源码23353
java·javascript·spring boot·python·eclipse·django·php
宿6745 小时前
tsconfig.node.json
前端·javascript·vue.js
小杨互联网5 小时前
Cursor 前端 Dist 自动化逆向框架:/fr 流水线 · 4 脚本 · Vite/Webpack
前端·webpack·自动化·前端逆向框架·ai前端逆向框架
瑞码空间5 小时前
Web应用的多端部署之道:浏览器 · Electron · Docker
前端·docker·electron·浏览器·web
徐奥雯XUAOWEN5 小时前
Codex官网前端可抄吗?从技术视角深度解析与借鉴指南
前端
文艺理科生5 小时前
3 年,8 种方案,1 次重构:LangChain 记忆方案如何从混乱走向清晰
前端·后端·架构
iReachers5 小时前
HTML打包APK实现拍照、录像、录音和文件选择教程
html·安卓·相机·apk打包·麦克风
lilian2335 小时前
Harmony os 技术实战|拼豆制图10:把取消、解析失败和保存失败写成可恢复状态机
java·javascript·华为·harmonyos