其他分享
首页 > 其他分享> > 令人头秃的树形表格自由拖拽实现(vue+ant+Sortable)

令人头秃的树形表格自由拖拽实现(vue+ant+Sortable)

作者:互联网

最近项目提出目标,须实现树状表格自由拖拽,并可支持antdesign(elementui)一类ui框架表格部分功能,紧张的项目周期让人心情久久难以平复,这是连百度的回答都难以让我释怀的痛。没法自己撸呗,代码核心难点在于拖拽后需同步数据结构及同步表格视图。献祭无数根头发后,终成目标。实现效果如下(额外功能可根据antdesign配置属性自行添加):

代码如下 :

<template>
  <div>
    <a-table
      v-if="tableShow"
      :columns="columns"
      :data-source="dataList"
      :pagination="false"
      @expandedRowsChange="expandedTable"
      :expandedRowKeys="expandKeysList"
      rowKey="id"
    >
    </a-table>
  </div>
</template>
<script>
import Sortable from 'sortablejs'
export default {
  name: 'commonTable',
  data () {
    return {
      tableShow: true,
      columns: [
        {
          title: 'Name',
          dataIndex: 'name',
          key: 'name',
          scopedSlots: { customRender: 'name' }
        },
        {
          title: 'Age',
          dataIndex: 'age',
          key: 'age',
          width: '12%',
          scopedSlots: { customRender: 'age' }
        },
        {
          title: 'Address',
          dataIndex: 'address',
          width: '30%',
          key: 'address',
          scopedSlots: { customRender: 'address' }
        }
      ],
      dataList: [
        {
          key: 1313123,
          id: 1,
          name: '1',
          age: 60,
          address: 'New York No. 1 Lake Park',
          children: [
            {
              key: 11,
              name: '2',
              age: 42,
              address: 'New York No. 2 Lake Park',
              parentId: '1',
              id: '11'
            },
            {
              key: 12,
              name: '3',
              age: 30,
              address: 'New York No. 3 Lake Park',
              parentId: '1',
              id: '12',
              children: [
                {
                  key: 121,
                  id: '121',
                  name: '4',
                  age: 16,
                  address: 'New York No. 3 Lake Park',
                  parentId: '12'
                }
              ],
            },
            {
              key: 13,
              id: '13',
              parentId: '1',
              name: '5',
              age: 72,
              address: 'London No. 1 Lake Park',
              children: [
                {
                  key: 131,
                  parentId: '13',
                  id: '131',
                  name: '6',
                  age: 42,
                  address: 'London No. 2 Lake Park',
                  children: [
                    {
                      parentId: '131',
                      id: '1311',
                      key: 1311,
                      name: '7',
                      age: 25,
                      address: 'London No. 3 Lake Park',
                    },
                    {
                      parentId: '131',
                      id: '1312',
                      key: 1312,
                      name: '8',
                      age: 18,
                      address: 'London No. 4 Lake Park',
                    },
                  ],
                },
              ],
            },
          ],
        },
        {
          key: 2,
          id: '2',
          name: '9',
          age: 32,
          address: 'Sidney No. 1 Lake Park',
        }
      ],
      expandKeysList: []
    }
  },
  methods: {
    expandedTable (keys) {
      if (this.tableShow) {
        this.expandKeysList = keys
      }
      this.refreshTable()
    },
    inintDrag () {
      let sortDom = document.querySelector('.ant-table-tbody')
      let _this = this
      Sortable.create(sortDom, {
        onStart ({ item }) {
          let targetRowKey = item.dataset.rowKey
          if (targetRowKey) {
            _this.expandKeysList = _this.expandKeysList.filter(item => item.toString() !== targetRowKey.toString())
          }
        },
        onEnd ({ newIndex, item }) {
          let targetRowKey = item.dataset.rowKey
          let targetArray = []
          let dataListItem = {}
          let targetItem = {}
          if (targetRowKey) {
            targetArray = _this.getTargeIndex(_this.dataList, targetRowKey.toString())
          }
          targetArray.forEach((item, index) => {
            item = parseInt(item)
            if (index < targetArray.length - 1) {
              if (!index) {
                targetItem = _this.dataList[item]
              } else {
                targetItem = targetItem.children[item]
              }
            } else {
              if (!index) {
                targetItem = JSON.stringify(_this.dataList[item])
                _this.dataList.splice(item, 1)

              } else {
                let calcItem = JSON.stringify(targetItem.children[item])
                targetItem.children.splice(item, 1)
                if (!targetItem.children.length) {
                  delete targetItem.children
                }
                targetItem = calcItem
              }
            }
          })
          if (newIndex > 0) {
            let isNext = false
            let currentRowKey = document.querySelectorAll('.ant-table-row')[newIndex - 1].dataset.rowKey
            if (document.querySelectorAll('.ant-table-row')[newIndex + 1]) {
              currentRowKey = document.querySelectorAll('.ant-table-row')[newIndex + 1].dataset.rowKey
              isNext = true
            }
            let currentArray = []
            if (currentRowKey) {
              currentArray = _this.getTargeIndex(_this.dataList, currentRowKey.toString())
            }
            currentArray.forEach((item, index) => {
              item = parseInt(item)
              if (index < currentArray.length - 1) {
                if (!index) {
                  dataListItem = _this.dataList[item]
                } else {
                  dataListItem = dataListItem.children[item]
                }
              } else {
                if (!index) {
                  if (!isNext) {
                    _this.dataList.splice(item + 1, 0 , JSON.parse(targetItem))
                  } else {
                    _this.dataList.splice(item, 0 , JSON.parse(targetItem))
                  }
                } else {
                  if (!isNext) {
                    dataListItem.children.splice(item + 1, 0, JSON.parse(targetItem))
                  } else {
                    dataListItem.children.splice(item, 0, JSON.parse(targetItem))
                  }
                }
              }
            })
          } else {
            _this.dataList.unshift(JSON.parse(targetItem))
          }
          _this.dataList = JSON.parse(JSON.stringify(_this.dataList))
          _this.refreshTable()
        }
      })
    },
    getTargeIndex (list, id, arr = []) {
      return list.reduce((total, item, index) => {
        if (item.id.toString() === id) {
          return [...total, index]
        } else {
          if (item.children && item.children.length) {
            let childArr = this.getTargeIndex(item.children, id, [...arr, index])
            if (childArr.length === [...arr, index].length) {
              childArr = total
            }
            return childArr
          } else {
            return total
          }
        }
      }, arr)
    },
    refreshTable () {
      this.tableShow = false
      this.$nextTick(() => {
        this.tableShow = true
        this.$nextTick(() => {
          this.inintDrag()
        })
      })
    }
  },
  mounted () {
    this.inintDrag()
  }
}
</script>

标签:index,vue,Sortable,name,targetItem,id,ant,item,children
来源: https://blog.csdn.net/weixin_43951323/article/details/120970155