vue基于SortableJS实现表格拖动排序

Posted 水星记_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue基于SortableJS实现表格拖动排序相关的知识,希望对你有一定的参考价值。

前言

大家都知道element中的树形控件要想拖动排序,我们只需要设置其draggable属性即可,但是在表格中要如何实现该操作呢?element官网中并没有提到,但是我们可以基于一些第三方的插件实现,今天给大家分享一个功能强大的javascript拖拽库—SortableJS。


安装

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 中文网


拓展

有关于 element 中树形控件(el-tree)如何实现拖动效果,大家可移步博主另一篇文章(vue基于element树形控件实现上下拖拽)

以上是关于vue基于SortableJS实现表格拖动排序的主要内容,如果未能解决你的问题,请参考以下文章

vue+vuedraggable实现拖动排序和删除

vue中使用sortable.js实现拖动排序

2021-04-25elementUI表格拖拽排序

element+sortablejs插件实现拖拽排序效果

vue drag 对表格的列进行拖动排序

基于vue实现可拖动弹框