拖拽排序功能

316 阅读1分钟

列表拖拽排序功能

实现步骤与思路

  1. 创建列表数据并渲染到页面
  2. 列表中需添加draggable="true"
  3. 列表中需添加dragstart dragenter dragend dragover 事件
  4. dragenter 事件中,需要传入列表项的下标,实时进行元素的排序,排序的核心逻辑也是在 dragenter 中
  5. 代码执行的逻辑是:列表项拖拽到可放置目标时,将该拖拽的元素从原位置删除,再将拖拽的元素插入到当前可放置目标的位置

代码实现

<template>
    <TransitionGroup name="list" tag="div" class="container">
        <div
            v-for="(item, i) in drag.list"
            :key="item.id"
            class="item"
            draggable="true"
            @dragstart="dragstart($event, i)"
            @dragenter="dragenter($event, i)"
            @dragend="dragend"
            @dragover="dragover"
        >
            {{ item.name }}
        </div>
    </TransitionGroup>
</template>

<script lang="ts" setup>
const drag = reactive({
    list: [
        { name: "a", id: 1 },
        { name: "b", id: 2 },
        { name: "c", id: 3 },
        { name: "d", id: 4 },
        { name: "e", id: 5 },
    ],
});

let dragIndex = 0;

const dragstart = (e: any, index: number) => {
    e.stopPropagation();
    dragIndex = index;
    setTimeout(() => {
        e.target.classList.add("moveing");
    }, 0);
};

const dragenter = (e: { preventDefault: () => void }, index: number) => {
    e.preventDefault();
    // 拖拽到原位置时不触发
    if (dragIndex !== index) {
        const source = drag.list[dragIndex];
        drag.list.splice(dragIndex, 1);
        drag.list.splice(index, 0, source);

        // 更新节点位置
        dragIndex = index;
    }
};

const dragover = (e: any) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = "move";
};

const dragend = (e: any) => {
    e.target.classList.remove("moveing");
    //排序后的数组数据
    console.log(drag.list);
};
</script>
<style lang="scss" scoped>
.item {
    width: 200px;
    height: 40px;
    line-height: 40px;
    background-color: skyblue;
    text-align: center;
    margin: 10px;
    color: #fff;
    font-size: 18px;
}
.container {
    position: relative;
    padding: 0;
}
.moveing {
    opacity: 0;
}

/* 对移动中的元素应用的过渡 */
.list-move, 
    .list-enter-active,
    .list-leave-active {
    transition: all 0.2s ease;
}
</style>

补充:可使用Vue中 <TransitionGroup> 内置组件来添加动画效果。

image.png

使用sortable.js进行表格排序

  1. 安装
npm i sortablejs -S
  1. 使用el-table写一个表格
<template>
    <div>
        <el-table id="dragTable" :data="tableData" border style="width: 800px">
            <el-table-column prop="date" label="Date" width="180" />
            <el-table-column prop="name" label="Name" width="180" />
            <el-table-column prop="address" label="Address" />
            <el-table-column label="操作" width="100">
                <template #default>
                    <div class="handle-drag">
                        <el-icon>
                            <Sort />
                        </el-icon>
                    </div>
                </template>
            </el-table-column>
        </el-table>
    </div>
</template>

<script lang="ts" setup>
// 引入sortablejs
import Sortable from "sortablejs";
// 引入icon图标
import { Sort } from "@element-plus/icons-vue";

// 表格数据源
const tableData = [
    {
        date: "2016-05-03",
        name: "Tom",
        address: "No. 189, Grove St, Los Angeles",
    },
    {
        date: "2016-05-02",
        name: "Cilly",
        address: "No. 189, Grove St, Los Angeles",
    },
    {
        date: "2016-05-04",
        name: "Linda",
        address: "No. 189, Grove St, Los Angeles",
    },
    {
        date: "2016-05-01",
        name: "John",
        address: "No. 189, Grove St, Los Angeles",
    },
];

// 排序
const setSort = () => {
    const el = document.querySelector("#dragTable table tbody");
    new Sortable(el, {
        sort: true,
        ghostClass: "sortable-ghost",
        // 配置表示只有包含`.handle-drag` 样式的元素才可以被拖动,其他位置不能被拖动。
        handle: ".handle-drag",
        onEnd: (e: { oldIndex: number; newIndex: number }) => {
            const targetRow = tableData.splice(e.oldIndex, 1)[0];
            tableData.splice(e.newIndex, 0, targetRow);
            // 排序之后的数据源
            console.log(tableData);
        },
    });
};

onMounted(() => {
    setSort();
});
</script>

<style lang="scss" scoped></style>

image.png

其他更多配置项