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>
相关推荐
ITresearchGuest5 小时前
LangChain JS 入门:快速搭建前端 AI 开发环境
前端·javascript·langchain
YHHLAI5 小时前
React + TypeScript 实战:从零构建颜色选择器应用
前端·react.js·typescript
小磊哥er5 小时前
深入解构Claude Code - 第 1 篇 · 先认识它
javascript·ai编程
Profile排查笔记5 小时前
指纹浏览器手机版怎么选?从本地 App 到云端 Android 的实现方式解析
前端·人工智能·后端·自动化
雪芽蓝域zzs5 小时前
第十节:动态侧边栏菜单(根据路由 meta 自动渲染菜单)
javascript·vue.js·elementui
浪兎兎5 小时前
Vue CLI笔记
前端·vue.js·笔记
Csvn5 小时前
Proxy / Reflect 与响应式原理:完整手写一个 mini Vue3 响应式系统
前端
Easy_API5 小时前
OpenAI三周内第二次降价,GPT-5.6 Sol砍了20%到33
大数据·前端·人工智能·gpt·深度学习
深念Y5 小时前
07-SSR水合问题实战排查与修复记录
前端·vue·vite·nuxt·ssr·csr·水合
前端炒粉5 小时前
容器预热预跳转方案
前端·vue.js·性能优化