用vue和sortableJS轻松实现表格拖拽排序

本文介绍如何使用Vue和SortableJS实现表格及树形表格的拖动排序功能,提高数据展示灵活性与用户操作效率。

前言

表格是数据展示中常用的形式之一,而拖动排序功能则可以提高用户操作效率。本文将介绍如何使用 vuesortableJS 实现表格拖动排序,让数据展示更加灵活和高效。


安装

npm install sortablejs --save
cnpm install sortablejs --save

引入

import Sortable from 'sortablejs'

使用

el-table 中必须加上 row-key="id",否则可能会导致排序不成功。原因是因为 vue 的加载循环机制,在进行删除时,一定要添加 key,跟使用 v-for 循环一样都需要添加绑定 key 值。

基础表格拖动排序

在这里插入图片描述


源码如下

<template>
  <div>
    <!-- 表格控件 -->
    <el-table :data="tableData" ref="tableNode" border highlight-current-row row-key="id">
      <el-table-column prop="name" label="姓名" align="center"></el-table-column>
      <el-table-column prop="sex" label="性别" align="center"></el-table-column>
      <el-table-column prop="age" label="年龄" align="center"></el-table-column>
      <el-table-column prop="address" label="地址" align="center"></el-table-column>
    </el-table>
  </div>
</template>

<script>
import Sortable from "sortablejs"; //引入下载的插件
export default {
  data() {
    return {
      // 模拟数据
      tableData: [
        {
          id: "1",
          name: "第一",
          sex: "男",
          age: "12",
          address: "北京",
        },
        {
          id: "2",
          name: "第二",
          sex: "男",
          age: "23",
          address: "上海",
        },
        {
          id: "3",
          name: "第三",
          sex: "女",
          age: "21",
          address: "广州",
        },
        {
          id: "4",
          name: "第四",
          sex: "女",
          age: "12",
          address: "深圳",
        },
      ],
    };
  },
  mounted() {
    this.pullSort(); //声明表格拖动排序方法
  },
  methods: {
    //表格拖动排序方法
    pullSort() {
      // 通过ref获取Dom节点
      const el = this.$refs.tableNode.$el.querySelectorAll(
        ".el-table__body-wrapper > table > tbody"
      )[0];
      this.sortable = Sortable.create(el, {
        animation: 600, //拖拽动画(毫秒)
        setData: function (dataTransfer) {
          dataTransfer.setData("Text", "");
        },
        // 结束拖拽
        onEnd: (e) => {
          //e.oldIndex为拖动一行原来的位置;e.newIndex为拖动后新的位置
          const oldRow = this.tableData[e.oldIndex]; // 移动元素集合
          const newRow = this.tableData[e.newIndex]; // 新的元素集合
          console.log(oldRow, "移动元素集合");
          console.log(newRow, "新的元素集合");
          // 调用接口传参即可
        },
      });
    },
  },
};
</script>

树形结构表格拖动排序

在这里插入图片描述


树形表格拖动不同于简单的表格拖动,我们要考虑到树形表格每一层的层级,如果返回的数据没有层级,我们需要给树形的数据去添加每一层的层级,其次,我们还得将树形表格数据转化为平铺数据在进行拖动,如果不转换的话,后面拖动的位置就是不对的,就会出错了,下面看代码实例。

源码如下

<template>
  <div>
    <!-- 表格树控件 -->
    <el-table :data="tableData" ref="tableNode" border highlight-current-row row-key="id">
      <el-table-column prop="label" label="模块" align="center"></el-table-column>
    </el-table>
  </div>
</template>

<script>
import Sortable from "sortablejs"; //引入下载的插件
// import { treeSort } from "@/api/system";//引入接口方法
export default {
  data() {
    return {
      // 模拟数据,实际情况根据后台返回数据调整
      tableData: [
        {
          id: "2619",
          label: "菜单一",
          parentId: "79f32a6fdbaisdaishdadhsd0b3540e17a0a",
        },
        {
          id: "4d1dd2a5wd3s2f1a5fd1as8f6869dc7b",
          label: "菜单二",
          parentId: "79f32a6fdbaisdaishdadhsd0b3540e17a0a",
          children: [
            {
              id: "4006",
              label: "A-1",
              parentId: "4d1dd2a5wd3s2f1a5fd1as8f6869dc7b",
            },
          ],
        },
        {
          id: "52cqw8r7f4a65s3d1a5f4s65a3d2w1507f93",
          label: "菜单三",
          parentId: "79f32a6fdbaisdaishdadhsd0b3540e17a0a",
          children: [
            {
              id: "4005",
              label: "B-1",
              parentId: "52cqw8r7f4a65s3d1a5f4s65a3d2w1507f93",
            },
          ],
        },
        {
          id: "66d5a4s13d2c1as5f4a6w5s13das12a89",
          label: "菜单四",
          parentId: "79f32a6fdbaisdaishdadhsd0b3540e17a0a",
          children: [
            {
              id: "3033",
              label: "C-1",
              parentId: "66d5a4s13d2c1as5f4a6w5s13das12a89",
            },
            {
              id: "3034",
              label: "C-2",
              parentId: "66d5a4s13d2c1as5f4a6w5s13das12a89",
            },
          ],
        },  
      ],
      activeRows: [], // 转换为列表的数据
    };
  },
  mounted() {
    this.pullSort(); //声明表格拖动排序方法
  },
  methods: {
    //拖拽排序
    pullSort() {
      const tbody = this.$refs.tableNode.$el.querySelectorAll(".el-table__body-wrapper > table > tbody")[0];
      const _this = this;//防止this指向问题
      Sortable.create(tbody, {
        animation: 600,
        onMove({ dragged, related }) {
          _this.$set(_this,"tableData",_this.arrayTreeSetLevel(_this.tableData)); // 树形结构数据添加level
          _this.activeRows = _this.treeToTile(_this.tableData); // 把树形的结构转为列表再进行拖拽
        },
        onEnd(e) {
          //e.oldIndex为拖动一行原来的位置,e.newIndex为拖动后新的位置
          if (e.oldIndex !== e.newIndex) {
            const oldRow = _this.activeRows[e.oldIndex]; // 移动元素
            const newRow = _this.activeRows[e.newIndex]; // 新的元素
            // level 当前层级  parentId 父级id
            if (oldRow.level != newRow.level || oldRow.parentId != newRow.parentId) {
              //不能跨级拖拽
              _this.$message({
                message: "只允许同级拖拽",
                type: "warning",
              });
              _this.tableData = [];//清空列表数据
              // _this.getTableTree();//调用列表接口
              return false;
            } else {
              // // 接口参数
              // let data = {
              //   previousId: oldRow.id,
              //   lastId: newRow.id,
              // };
              // // 请求接口
              // treeSort(data).then((res) => {
              //   if (res.code == "10000") {
              //     _this.tableData = [];//清空列表数据
              //     _this.getTableTree();//调用列表接口
              //     _this.$message({
              //       message: res.msg,
              //       type: "success",
              //     });
              //   }
              // });
            }
          }
        },
      });
    },
    // 给树形的数据去添加每一层的层级
    arrayTreeSetLevel(array, levelName = "level", childrenName = "children") {
      if (!Array.isArray(array)) {
        return [];
      }
      const recursive = (array, level = 0) => {
        level++;
        return array.map((v) => {
          v[levelName] = level;
          const child = v[childrenName];
          if (child && child.length) {
            recursive(child, level);
          }
          return v;
        });
      };
      return recursive(array);
    },
    // 将树数据转化为平铺数据
    treeToTile(treeData, childKey = "children") {
      const arr = [];
      const expanded = (data) => {
        if (data && data.length > 0) {
          data
            .filter((d) => d)
            .forEach((e) => {
              arr.push(e);
              expanded(e[childKey] || []);
            });
        }
      };
      expanded(treeData);
      return arr;
    },
  },
};
</script>

总结

SortableJS 为开发者提供了多种拖动效果,单列表、多列表、嵌套排序等等都不在话下,大家感兴趣的话可以去官网查看: SortableJS 中文网


相关推荐

vue+element实现树形上下拖拽,快速提升你的前端技能
教你一招,element表格行轻松上下移动

在使用 SortableJS 结合 Element UI 实现表格列的拖拽排序功能时,可以通过操作 DOM 元素并绑定 SortableJS拖拽能力来实现。由于 Element UI 的 `el-table` 组件本身并不支持列拖拽排序,因此需要借助 SortableJS 提供的 API 来实现。 ### 实现步骤 #### 1. 安装依赖 首先,确保项目中已经安装了 `element-ui` `sortablejs`。如果尚未安装,可以通过以下命令进行安装: ```bash npm install element-ui sortablejs --save ``` 或使用 yarn: ```bash yarn add element-ui sortablejs ``` [^2] #### 2. 在组件中引入 在需要使用的 Vue 组件中引入 `el-table` `Sortable`: ```javascript import { Table, TableColumn } from 'element-ui'; import Sortable from 'sortablejs'; ``` #### 3. 创建表格并初始化 SortableJS 在 `mounted` 生命周期钩子中初始化 `Sortable`,并对 `el-table` 的列标题进行拖拽排序绑定。以下是一个完整的代码示例: ```vue <template> <el-table :data="tableData" border ref="tableRef"> <el-table-column v-for="column in columns" :key="column.prop" :prop="column.prop" :label="column.label" /> </el-table> </template> <script> import { Table, TableColumn } from 'element-ui'; import Sortable from 'sortablejs'; export default { components: { 'el-table': Table, 'el-table-column': TableColumn }, data() { return { tableData: [ { id: 1, name: '张三', age: 25 }, { id: 2, name: '李四', age: 30 }, { id: 3, name: '王五', age: 28 } ], columns: [ { prop: 'id', label: 'ID' }, { prop: 'name', label: '姓名' }, { prop: 'age', label: '年龄' } ] }; }, mounted() { this.initColumnDrag(); }, methods: { initColumnDrag() { const wrapper = this.$refs.tableRef.$el.querySelector('.el-table__header-wrapper .el-table__header thead tr'); Sortable.create(wrapper, { animation: 150, ghostClass: 'sortable-ghost', onEnd: (evt) => { const oldIndex = evt.oldIndex; const newIndex = evt.newIndex; const movedColumn = this.columns.splice(oldIndex, 1)[0]; this.columns.splice(newIndex, 0, movedColumn); } }); } } }; </script> <style> .sortable-ghost { opacity: 0.6; background-color: #b4b4b4; } </style> ``` 在上述代码中,`Sortable.create` 方法用于初始化列标题的拖拽功能。`onEnd` 回调用于在拖拽结束后更新 `columns` 数组的顺序,从而实现列顺序的同步更新。 #### 4. 数据一致性处理 为了确保拖拽后的列顺序能够正确反映在数据中,可以在 `onEnd` 中对数据结构进行调整,例如更新后端接口传递的字段顺序或重新渲染表格数据[^4]。 ### 注意事项 - 确保在 `mounted` 生命周期中初始化 `Sortable`,因为此时 DOM 元素已经渲染完成。 - 使用 `ref` 获取 `el-table` 实例,以便操作其内部 DOM 结构。 - 在拖拽过程中,建议使用 `ghostClass` 样式来提升用户体验。 - 如果表格中使用了 `row-key`,确保数据结构与列顺序保持一致,避免数据错位。
评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水星记_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值