天天看点

踩坑日记 - Sortable 拖动树表格排序觉得有帮助的小伙伴记得点个赞鼓励下~扫描上方二维码关注我的订阅号~

以 Element 树表格为例,实现了树表格的同级之间排序(跨级也有代码,但还有问题)

踩坑点:

  • onMove回调中 oldIndex 会随时变化,若想拿到最开始拖动的Row,需要使用onChoose 。
  • 在onChoose需将 oldIndex 或者 oldRow 存储一下,供后续onMove和onEnd使用。
  • onMove 中可以使用return false 阻止拖动
  • 因为是树形结构,所以回调中返回的 Index 并不准确,所以要预先在onChoose 时将树数据扁平化,才能根据返回的Index获取到对应的Row。
  • 拖动结束更改树表格源数据,虽然数据有更改,但视图可能会乱掉,所以要使用nexttick 更新数据
  • 更新数据后默认树会缩合,所以要设置需要展开的节点

上代码

<el-table
  ref="ruleSelectTableRef"
  v-loading="isLoading"
  row-key="ruleTagId"
  :data="tableData"
  border
  :max-height="500"
>
  <el-table-column label="" width="45"></el-table-column>
  <el-table-column width="40" :render-header="selectAllHeaderRender">
    <template slot-scope="scope">
      <el-checkbox
        v-model="scope.row.isSelected"
        :disabled="scope.row.isDisabled"
        @change="val => selectRow(val, scope.row)"
      ></el-checkbox>
    </template>
  </el-table-column>
  <el-table-column label="设备类" prop="packageName"></el-table-column>
  <el-table-column label="操作" prop="handles" width="80" fixed="right">
    <template slot-scope="scope">
      <el-button
        v-if="scope.row.level !== 1"
        type="text"
        :class="{ 'text-btn-red': scope.row.compareOnline }"
        @click="showLogModule(scope.row)"
      >
        查看日志
      </el-button>
    </template>
  </el-table-column>
</el-table>


import Sortable from 'sortablejs';
import { deepClone } from '@/utils/util';
import { nextTick } from 'process';


private selectedTableData: IListRuleCollectionRuleSelectInfo[] = [];
private flatSelectedTableData: any[] = [];
private drawOldIndex: any = -1;

// 将树数据转化为平铺数据
flatTreeData(treeData: any[], childKey = 'children') {
  const arr: any[] = [];
  const expanded = (data: any) => {
    if (data && data.length > 0) {
      data
        .filter((d: any) => d)
        .forEach((e: any) => {
          arr.push(e);
          expanded(e[childKey] || []);
        });
    }
  };
  expanded(treeData);
  return arr;
}

// 行拖拽
rowDrop() {
  // 此时找到的元素是要拖拽元素的父容器
  const tbody = document.querySelector('#selected-table .el-table__body-wrapper tbody');
  const that = this;
  Sortable.create(tbody, {
    // 指定父元素下可被拖拽的子元素
    draggable: '.el-table__row',
    setData: function (dataTransfer: any) {
      dataTransfer.setData('Text', '');
    },
    onChoose({ oldIndex }: any) {
      // 把树形的结构转为列表再进行拖拽
      that.$set(that, 'flatSelectedTableData', that.flatTreeData(that.selectedTableData));
      that.drawOldIndex = oldIndex;
    },
    onMove({ related }: any) {
      const oldRow: any = that.flatSelectedTableData[that.drawOldIndex];
      const newRow: any = that.flatSelectedTableData[related.rowIndex];
      // if (!newRow || !newRow.id || !oldRow || !oldRow.id) return false;
      // 拖动的是一个包
      if (oldRow.level === 1) {
        if (newRow.level === 1 && oldRow.id === newRow.id) return false;
        // 还在自己的包里面
        if (oldRow.rulePackageId === newRow.newPackageId) return false;
      } else {
        // 不是包不可以挪到最上面
        if (related.rowIndex === 0) return false;
        // 跨包不允许
        if (oldRow.newPackageId !== newRow.newPackageId || newRow.level === 1) return false;
      }
    },
    onEnd({ newIndex, oldIndex }: any) {
      if (oldIndex !== newIndex) {
          const oldRow: any = that.flatSelectedTableData[oldIndex];
          const newRow: any = that.flatSelectedTableData[newIndex];
          const selectedTableData = deepClone(that.selectedTableData);
          that.selectedTableData = [];
          const expansionRowKey: any[] = [];
          // 拖动的是一个包
          if (oldRow.level === 1) {
            expansionRowKey.push(oldRow.id);
            // 找到拖动的这个包
            const currPackageIndex = selectedTableData.findIndex((p: any) => p.id === oldRow.id);
            // 找到新包的位置塞进去
            // 新位置是一个包的位置 (包 -> 包)
            if (newRow.level === 1) {
              const newPackageIndex = selectedTableData.findIndex((p: any) => p.id === newRow.id);
              const currPackage = selectedTableData.splice(currPackageIndex, 1)[0];
              selectedTableData.splice(newPackageIndex, 0, currPackage);
              expansionRowKey.push(newRow.id);
              // 新位置是一个行的位置 (包 -> 行)
            } else {
              // 找到这个行的父级包
              const newPackageIndex = selectedTableData.findIndex((p: any) => p.newPackageId === newRow.newPackageId);
              // 删掉原来的包,放到新包的后面
              const currPackage = selectedTableData.splice(currPackageIndex, 1)[0];
              selectedTableData.splice(newPackageIndex, 0, currPackage);
              expansionRowKey.push(selectedTableData[newPackageIndex].id);
            }
            // 拖动的是一个行
          } else {
            // 新目标是一个包 (行 -> 包)
            if (newRow.level === 1) {
              expansionRowKey.push(newRow.id);
              // 如果还是原来的包(包内排序移到开头)
              if (oldRow.newPackageId === newRow.newPackageId) {
                // 找到当前包位置
                const newPackageIndex = selectedTableData.findIndex((p: any) => p.id === newRow.id);
                const currPackage = selectedTableData[newPackageIndex];
                expansionRowKey.push(currPackage.id);
                const currPackageChildren = currPackage?.children || [];
                // 找到拖动的行在children 中的 index
                const currRuleIndex = currPackageChildren.findIndex((rule: any) => rule.ruleTagId === oldRow.ruleTagId);
                const currRule = currPackageChildren.splice(currRuleIndex, 1)[0];
                // 放到最开头
                currPackageChildren.splice(0, 0, currRule);
                currPackage.children = currPackageChildren;
                // 替换掉原来的包
                selectedTableData.splice(newPackageIndex, 1, currPackage);
                // 如果在另外一个包开头(废弃,目前不允许,还有问题)
              } else {
                return false;
                // 找到旧包
                // const oldPackageIndex = selectedTableData.findIndex((p: any) => p.newPackageId === oldRow.newPackageId);
                // const oldPackage = selectedTableData[oldPackageIndex];
                // expansionRowKey.push(oldPackage.id);
                // const oldPackageChildren = oldPackage?.children || [];
                // // 删掉旧包中的 old rule
                // const oldRuleIndex = oldPackageChildren.findIndex((rule: any) => rule.ruleTagId === oldRow.ruleTagId);
                // const oldRule = oldPackageChildren.splice(oldRuleIndex, 1)[0];
                // // 找到新包
                // const newPackageIndex = selectedTableData.findIndex((p: any) => p.id === newRow.id);
                // const newPackage = selectedTableData[newPackageIndex];
                // const newPackageChildren = newPackage?.children || [];
                // // 新包中增加 该 rule
                // newPackageChildren.splice(0, 0, oldRule);
                // // 覆盖原包
                // oldPackage.children = oldPackageChildren;
                // newPackage.children = newPackageChildren;
                // selectedTableData.splice(oldPackageIndex, 1, oldPackage);
                // selectedTableData.splice(newPackageIndex, 1, newPackage);
              }
              // 新位置是一个行的位置 (行 -> 行)
            } else {
              // 还在原来的包内(包内排序)
              if (oldRow.newPackageId === newRow.newPackageId) {
                // 找到当前包位置
                const newPackageIndex = selectedTableData.findIndex((p: any) => p.newPackageId === newRow.newPackageId);
                const currPackage = selectedTableData[newPackageIndex];
                expansionRowKey.push(currPackage.id);
                const currPackageChildren = currPackage?.children || [];
                // 找到拖动的行在children 中的 index
                const oldRuleIndex = currPackageChildren.findIndex((rule: any) => rule.ruleTagId === oldRow.ruleTagId);
                // 找到将要排序到的目标位置
                const newRuleIndex = currPackageChildren.findIndex((rule: any) => rule.ruleTagId === newRow.ruleTagId);
                // 排序
                const oldRule = currPackageChildren.splice(oldRuleIndex, 1)[0];
                currPackageChildren.splice(newRuleIndex, 0, oldRule);
                currPackage.children = currPackageChildren;
                // 替换掉原来的包
                selectedTableData.splice(newPackageIndex, 1, currPackage);
                // 在另外一个包内(废弃,目前不允许,还有问题)
              } else {
                return false;
                // 找到旧包
                // const oldPackageIndex = selectedTableData.findIndex((p: any) => p.newPackageId === oldRow.newPackageId);
                // const oldPackage = selectedTableData[oldPackageIndex];
                // expansionRowKey.push(oldPackage.id);
                // const oldPackageChildren = oldPackage?.children || [];
                // // 删掉旧包中的 old rule
                // const oldRuleIndex = oldPackageChildren.findIndex((rule: any) => rule.ruleTagId === oldRow.ruleTagId);
                // // 找到新包
                // const newPackageIndex = selectedTableData.findIndex((p: any) => p.newPackageId === newRow.newPackageId);
                // const newPackage = selectedTableData[newPackageIndex];
                // expansionRowKey.push(newPackage.id);
                // const newPackageChildren = newPackage?.children || [];
                // // 找到 newRule 在 新包中的 index
                // const newRuleIndex = newPackageChildren.findIndex((rule: any) => rule.ruleTagId === newRow.ruleTagId);
                // const oldRule = oldPackageChildren.splice(oldRuleIndex, 1)[0];
                // // 新包中增加 该 rule
                // newPackageChildren.splice(newRuleIndex, 0, oldRule);
                // // 覆盖原包
                // oldPackage.children = oldPackageChildren;
                // newPackage.children = newPackageChildren;
                // selectedTableData.splice(oldPackageIndex, 1, oldPackage);
                // selectedTableData.splice(newPackageIndex, 1, newPackage);
              }
            }
          }
          that.$nextTick(() => {
            that.selectedTableData = selectedTableData;
            that.$nextTick(() => {
              that.selectedTableData.forEach((item: any) => {
                if (expansionRowKey.includes(item.id)) {
                  (that.$refs.ruleSelectedTableRef as any).toggleRowExpansion(item, true);
                }
              });
            });
          });
        }
    },
  });
}

           

觉得有帮助的小伙伴记得点个赞鼓励下~

踩坑日记 - Sortable 拖动树表格排序觉得有帮助的小伙伴记得点个赞鼓励下~扫描上方二维码关注我的订阅号~

扫描上方二维码关注我的订阅号~