当前位置: 首页 > 工具软件 > JSsearch > 使用案例 >

elementui列表组件(树数据)+sortable.js 实现仅同层级拖拽排序

公羊安怡
2023-12-01

前两天和产品哥哥说好的列表拖拽排序,突然就变成了树列表拖拽排序,还要限制不能跨父级拖拽,没法子,头发抓掉一把之后写出来了,不难,就是数学不太好,算了老半天

从引入sortable.js开始讲起吧,从0到1 (纯手打,可能会有字母写错,大家擦亮眼睛)

1、运行命令: npm install  sortablejs

2、在对应页面引入:import Sortable from 'sortablejs'

不墨迹,接下来展示全部代码

<template>
  <div class="attribute-manage padding-lg full-h over-hide">
      <VTable
        ref="vTable"
        :key="tableKey"
        :data="treeData"
        :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
        max-height="calc(100vh - 260px)"
        row-key="id"
        @search="onSearch"
      >
        <el-table-column prop="categoryName" label="分类名称" min-width="100px" show-overflow-tooltip />
        <el-table-column prop="level" label="级别" min-width="40px" show-overflow-tooltip />
        <el-table-column label="是否显示" min-width="50px">
          <template slot-scope="{ row }">
            <span>{{ row.isSpecialColumn === '1' ? '是' : '否' }}</span>
          </template>
        </el-table-column>
        <el-table-column prop="leaderName" label="品类负责人" min-width="50px" />
      </VTable>
  </div>
</template>

 注: VTable只是对el-table组件做的二次封装,统一样式而已,与el-table无太大差异

<script>
import Sortable from 'sortablejs'
export default {
  data () {
      return {
        treeData: [],  // 展示数据
        page: 1,
        limit: 15,
        sortable: null,  // sortable对象
        activeRows: new Array(0),  // 排序时用来跟后端进行数据交互
        tableKey: ''  // 这个蛮重要的,让dom刷新
      }
   },
   created () {
      this.initData()
   },
   methods: {
      async initData () {
        if (this.sortable && this.sortable.el) {
          this.sortable.destroy()
        }
        const { data } = await itemCategory.getAllList({ source: 1 })
        // 这里因为后端给了平级数据,所以要把它格式化成树结构
        this.$set(this, 'treeData', this.$utils.formatTree(data, { nodeKey: 'id', parentKey: 'parentId' }))
        // 这里是把树结构的数据再按照从上到下的顺序转化成平级数据,因为排序接口,后端要求是发送从上到下的平铺的id集合
        this.$set(this, 'activeRows', this.$utils.treeToTile(this.treeData))
        // 这里是给tableKey一个随机数,Math.random也可以的,只要跟上一次的值不一样,能让dom刷新就可以
        this.tableKey = new Date().getTime()
        this.$nextTick(() => {
          this.setSort()
        })
      },
      setSort () {
        const el = document.querySelectorAll('table.el-table__body > tbody')[0]

        if (!el) {
          return
        }
        let that = this
        this.sortable = Sortable.create(el, {
          ghostClass: 'sortable-ghost',
          setData: function (dataTransfer) {
            dataTransfer.setData('Text', '')
          },
          // 拖拽移动的时候
          onMove: function ({ dragged, related }) {
            // 对了,树数据中不管是哪一层,都一定要有level字段表示当前是第几层哦
            /*
              evt.dragged; // 被拖拽的对象
              evt.related; // 被替换的对象
             */
            const oldRow = that.activeRows[dragged.rowIndex]
            const newRow = that.activeRows[related.rowIndex]
            if (oldRow.level !== newRow.level || oldRow.parentId !== newRow.parentId) {
              return false
            }
          },
          onEnd: async ({ oldIndex, newIndex }) => {
            const oldRow = that.activeRows[oldIndex]
            const newRow = that.activeRows[newIndex]
            if (oldIndex !== newIndex && oldRow.level === newRow.level && oldRow.parentId === newRow.parentId) {
              const oldRow = that.activeRows[oldIndex]
              const newRow = that.activeRows[newIndex]
              let oldRowSuffixData = that.activeRows.slice(oldIndex)
              let newRowSuffixData = that.activeRows.slice(newIndex)

              oldRowSuffixData = oldRowSuffixData.filter((d, i) => i < that.getLeastIndex(oldRowSuffixData.findIndex((_d, _i) => _d.level === oldRow.level && _i !== 0)))
              newRowSuffixData = newRowSuffixData.filter((d, i) => i < that.getLeastIndex(newRowSuffixData.findIndex((_d, _i) => _d.level === newRow.level && _i !== 0)))
              const targetRows = that.activeRows.splice(oldIndex, oldRowSuffixData.length)

              if (oldIndex > newIndex) {
                that.activeRows.splice(newIndex, 0, ...targetRows)
              } else if (oldIndex < newIndex) {
                that.activeRows.splice(newIndex + newRowSuffixData.length - oldRowSuffixData.length, 0, ...targetRows)
              }
              await itemCategory.sort(that.activeRows.map(d => d.id))
              that.initData()
            }
          },
          onSort: function (/** Event */evt) {
            console.log('触发!')
          }
        })
        console.log()
      },
      getLeastIndex (index) {
        return index >= 1 ? index : 1
      }
   }
}
</script>

好人做到底吧! 

// 将树数据转化为平铺数据
export function treeToTile (treeData, childKey = 'children') {
  let 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
}

 让我有点成就感,有帮助到各位的话请点个赞呀~

 

 类似资料: