令人头秃的树形表格自由拖拽实现(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