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>
相关推荐
zqx_79 分钟前
随记 前端框架React的初步认识
前端·react.js·前端框架
惜.己26 分钟前
javaScript基础(8个案例+代码+效果图)
开发语言·前端·javascript·vscode·css3·html5
什么鬼昵称1 小时前
Pikachu-csrf-CSRF(get)
前端·csrf
长天一色1 小时前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript
NiNg_1_2341 小时前
npm、yarn、pnpm之间的区别
前端·npm·node.js
秋殇与星河1 小时前
CSS总结
前端·css
NiNg_1_2341 小时前
Vue3 Pinia持久化存储
开发语言·javascript·ecmascript
读心悦1 小时前
如何在 Axios 中封装事件中心EventEmitter
javascript·http
BigYe程普2 小时前
我开发了一个出海全栈SaaS工具,还写了一套全栈开发教程
开发语言·前端·chrome·chatgpt·reactjs·个人开发
神之王楠2 小时前
如何通过js加载css和html
javascript·css·html