sortablejs的应用及一些常见问题记录

3,486 阅读1分钟

一. 介绍

sortablejs是一款功能强大的JavaScript 拖拽库,我的使用一般是在table表格中使用,但它的功能远不止于此,这里只记录下在使用sortablejs进行table表格拖拽中遇到的问题。Vue3 element plus配合使用

二. 使用

1. 安装

npm i sortablejs -S

2. 引用

import Sortable from 'sortablejs';

3. 初始化使用

创建实例时传入两个参数,第一个为包裹的父元素,第二个为配置对象。 详情配置见中文官网sortablejs中文官网

<template>
 <div v-if='dialogFormVisible'>
 
      <el-table
          :data="nodeTableData"
          :row-key="nodeId"
          ref="myTable"
          :row-class-name="filter_row"
        >
          <el-table-column width="80" label="排序"></el-table-column>
          ...
          ...
      </el-table>
 </div>
</template>
<script>
  import { defineComponent, ref, watch, nextTick } from 'vue';
  import Sortable from 'sortablejs';
  
  export default defineComponent({
  setup() {
  
    let myTable = ref(null);
    let dialogFormVisible = ref(false)
  
    drag() {
        const el1 = myTable.value.$refs.tableBody.children[1];
        new Sortable(el1, {
         disabled: false, // 是否开启拖拽
         ghostClass: 'sortable-ghost', //拖拽样式
         animation: 150, // 拖拽延时,效果更好看
         filter: '.filter_row',
         group: {
          // 是否开启跨表拖拽
          pull: false,
          put: false,
         },
         onEnd: function(e) {
         // 这里主要进行数据的处理,拖拽实际并不会改变绑定数据的顺序,这里需要自己做数据的顺序更改
          if (e.oldIndex == e.newIndex) return;

          const currRow = nodeTableData.value.splice(e.oldIndex, 1)[0]; 
          nodeTableData.value.splice(e.newIndex, 0, currRow);

          if (e.newIndex === 0 || e.newIndex === nodeTableData.value.length - 1) {
            //复原数据
            let item = nodeTableData.value.splice(e.newIndex, 1)[0];
            nodeTableData.value.splice(e.oldIndex, 0, item);
            // 复原拖拽之前的 dom
            const tagName = e.item.tagName;
            const items = e.from.getElementsByTagName(tagName);
            if (e.oldIndex > e.newIndex) {
              e.from.insertBefore(e.item, items[e.oldIndex + 1]);
            } else {
              e.from.insertBefore(e.item, items[e.oldIndex]);
            }
            ElMessage.error('不可修改');
            return;
          }
          
          // 如数据有排序数据的需要去同步更改
          nodeTableData.value.forEach((item, index) => {
            item.nodeSort = index + 1;
          });
          if (!isAdd.value) {
            let needEditNode = [];
            let params = { list: [] };
            if (e.newIndex > e.oldIndex) {
              //下移
              needEditNode = nodeTableData.value.filter((item, index) => index >= e.oldIndex);
              params.list = needEditNode.map((item) => {
                return { nodeId: item.nodeId, nodeSort: item.nodeSort };
              });
              xxx(params);//发送的后台请求
            } else {
              //上移
              needEditNode = nodeTableData.value.filter((item, index) => index >= e.newIndex);
              params.list = needEditNode.map((item) => {
                return { nodeId: item.nodeId, nodeSort: item.nodeSort };
              });
              xxx(params);//发送的后台请求
            }
          }
         
         },
        })
      }
     
    watch(
      () => dialogFormVisible.value,
      (newV) => {
        if (newV) {
          nextTick(() => drag());
        }
      },
      { immediate: true },
    );
    
   return {
     myTable,
     dialogFormVisible
   }
   
   }
   })
</script>

三. 一些问题

1. 关于找不到元素的问题

这里的table表格是在一个弹框里的,由dialogFormVisible状态去显示隐藏,必须通过watch去监听当元素创建后在去做实例的初始化。如果只是页面中的table拖拽就比较简单不需要这样了。可通过打印去找到实际包裹的父元素。

2. filter配置问题

如果有需求说明那些行不可拖拽的,如(首行和尾行不可拖拽)可以使用element UI中table的row-class-name属性去自定义添加某行的类名。

3. 当filter后,当前元素是不可拖拽但其他元素还是可以拖拽到它的位置,影响需求。

可通过判断新拖拽到的位置是否是filter的行,在复原拖拽前的dom

if (e.newIndex === 0 || e.newIndex === nodeTableData.value.length - 1) {
              //复原数据
              let item = nodeTableData.value.splice(e.newIndex, 1)[0];
              nodeTableData.value.splice(e.oldIndex, 0, item);
              // 复原拖拽之前的 dom
              const tagName = e.item.tagName;
              const items = e.from.getElementsByTagName(tagName);
              if (e.oldIndex > e.newIndex) {
                e.from.insertBefore(e.item, items[e.oldIndex + 1]);
              } else {
                e.from.insertBefore(e.item, items[e.oldIndex]);
              }
              ElMessage.error('不可修改');
              return;
            }