> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# Vue 表单拖拽排序

## 业务需求：

因为数据展示使用的是 **elementUI** 的 **Table** 进行数据展示的，现在的需求是通过拖拽表单进行表单排序。同时，动态修改表单中的数据排列顺序。查阅了好多资料，也翻看了好多 github 上别人封装好的表单插件，但是最终都不是自己想要的，其中主要原因就是，后台管理系统页面中，同一个窗口可能涉及到多个 **表单拖拽排序**，与此同时，使用部分插件就有可能导致数据更新不及时，或者下次在使用的时候，数据无论如何赋值就是更新不成功，导致最终渲染的要拖拽的表单一会有数据，一会无数据的，体验很不好。

## 解决方案：

选取了好多封装好的插件，都没有达到自己想要的效果。偶然间看到有人提示使用原生拖拽的方式来解决表单托拖拽排序的问题。最终，我采用 **sortablejs** 结合原生 **DOM** 节点操作的方式，对表单元素数据进行剪切、拼接处理等方式，最终达到理想效果。

## 操作步骤：

- 首先安装 **sortablejs** 插件


```sh [npm]
npm install sortablejs
```

```sh [yarn]
yarn add sortablejs
```

```sh [pnpm]
pnpm add sortablejs
```

```sh [bun]
bun add sortablejs
```

```sh [deno]
deno add npm:sortablejs
```

- 引用 **sortablejs** 插件（全局使用，或组件内使用）

```javascript title="操作步骤："
import Sortable from "sortablejs";
```

- **Table** 相关代码

```html title="操作步骤："
<template>
    <div class="drag_table">
        <!-- row-key 排序依据的参数，此处不能使用 index 作为排序的依据 -->
        <!-- highlight-current-row：单击选中行高亮 -->
        <el-table
            :data="dragList"
            ref="dragTable"
            row-key="id"
            border
            stripe
            highlight-current-row
        >
            <el-table-column
                label="序号"
                type="index"
                width="50"
                align="center"
            ></el-table-column>
            <el-table-column
                label="ID"
                prop="id"
                align="center"
            ></el-table-column>
            <el-table-column
                label="姓名"
                prop="name"
                show-overflow-tooltip
            ></el-table-column>
            <!-- 性别判断，使用 prop 属性 -->
            <el-table-column label="性别" prop="sex">
                <template slot-scope="scope">
                    <el-tag>{{ scope.row.sex === 0 ? '女' : '男' }}</el-tag>
                </template>
            </el-table-column>
            <!-- 从排序表单中移除表单元素 -->
            <el-table-column label="操作" width="66" align="center">
                <template slot-scope="scope">
                    <el-button
                        type="danger"
                        icon="el-icon-delete"
                        plain
                        @click="delItem(scope.$index)"
                        >移除</el-button
                    >
                </template>
            </el-table-column>
        </el-table>
    </div>
</template>
```

- JavaScript 逻辑代码

```javascript title="操作步骤："
// 引入排序插件
import Sortable from "sortablejs";

export default {
    name: "DragTable",
    data() {
        return {
            sortable: null /* 表单拖拽 */,
            dragList: [
                {
                    id: 1,
                    name: "张三",
                    sex: 1,
                },
                {
                    id: 2,
                    name: "李四",
                    sex: 0,
                },
                {
                    id: 3,
                    name: "王五",
                    sex: 0,
                },
                {
                    id: 4,
                    name: "赵六",
                    sex: 1,
                },
            ],
        };
    },
    mounted() {
        // 等待数据渲染完成再加初始化拖拽表单
        this.$nextTick(() => {
            this.initSortTable();
        });
    },
    methods: {
        // 移除数据
        delItem(index) {
            this.dragList.splice(index, 1);
        },
        // 初始化拖拽表单
        initSortTable() {
            // const elTag = this.$refs['dragTable'].$el.querySelectorAll(".el-table__body-wrapper > table > tbody")[0];

            // 获取 el-table
            const tableTag = this.$refs["dragTable"].$el;

            // 获取 tbody 节点
            const elTbody = tableTag.querySelectorAll(
                ".el-table__body-wrapper > table > tbody"
            )[0];
            // 拖拽排序
            this.sortable = Sortable.create(elTbody, {
                onEnd: (evt) => {
                    const tempIndex = this.dragList.splice(evt.oldIndex, 1)[0];
                    this.dragList.splice(evt.newIndex, 0, tempIndex);
                },
            });
        },
    },
};
```
