问题
vue项目中使用了vxe-table加载组织机构列表,列表是树形结构的,需要实现同级组织机构通过拖拽进行排序的功能,而vxe-table官网上拖拽排序的demo没有同级节点的限制,而且存在一些bug,比如父节点向上拖拽时,子节点是和父节点一起移动的,但父节点向下拖拽时,子节点没有一起移动;Test2下的子节点拖拽到最后一行松开鼠标时位置不正确等等。下面给出一个我实现的同级节点拖拽排序功能,参考vxe-table的代码,做了很多调整,同样基于sortable.js实现。
排序代码
treeDrop() {
this.$nextTick(() => {
const xTable = this.$refs.xTree
if (!xTable) {
return
}
this.sortable = Sortable.create(xTable.$el.querySelector('.body--wrapper>.vxe-table--body tbody'), {
handle: '.drag-btn',
onEnd: ({ item, oldIndex }) => {
const options = { children: 'children' }
const wrapperElem = item.parentNode
const targetTrElem = item
const alternativeTrElem = wrapperElem.children[oldIndex]
const prevTrElem = targetTrElem.previousElementSibling
const nextTrElem = targetTrElem.nextElementSibling
const tableTreeData = this.tableData
const selfNode = xe.findTree(tableTreeData, row => row.cguid === targetTrElem.getAttribute('rowid'), options)
const selfRow = selfNode.item
if (prevTrElem) {
const prevNode = xe.findTree(tableTreeData, row => row.cguid === prevTrElem.getAttribute('rowid'), options)
const prevRow = prevNode.item
if (xTable.isTreeExpandByRow(prevRow)) {
if (selfRow.parentorgnid !== prevRow.cguid) {
this.restore(wrapperElem, targetTrElem, alternativeTrElem)
this.$message({
type: 'warning',
message: '只能在同级节点移动!'
})
return
}
selfNode.items.splice(selfNode.index, 1)
selfNode.items.unshift(selfRow)
} else {
if (selfRow.parentorgnid !== prevRow.parentorgnid) {
if (xe.findTree(selfRow[options.children], row => prevRow === row, options)) {
this.restore(wrapperElem, targetTrElem, alternativeTrElem)
this.$message({
type: 'warning',
message: '只能在同级节点移动!'
})
return
}
let nextTrElemIsOnSameLevelWidthTargetTrElemBeforeMove = false
if (nextTrElem) {
const nextNode = xe.findTree(tableTreeData, row => row.cguid === nextTrElem.getAttribute('rowid'), options)
const nextRow = nextNode.item
if (selfRow.parentorgnid === nextRow.parentorgnid) {
nextTrElemIsOnSameLevelWidthTargetTrElemBeforeMove = true
}
}
if (nextTrElemIsOnSameLevelWidthTargetTrElemBeforeMove === false) {
this.restore(wrapperElem, targetTrElem, alternativeTrElem)
this.$message({
type: 'warning',
message: '只能在同级节点移动!'
})
return
}
}
selfNode.items.splice(selfNode.index, 1)[0]
const prevRowIndex = this.findPrevRowOrItsAncestorIndex(prevRow, selfNode)
selfNode.items.splice(prevRowIndex + 1, 0, selfRow)
if (this.isDraggedDown(targetTrElem, alternativeTrElem) && xTable.isTreeExpandByRow(selfRow)) {
let lastInsertTrElem = targetTrElem
while (oldIndex < wrapperElem.children.length) {
const trElem = wrapperElem.children[oldIndex]
const isSiblingNodes = selfNode.items.some(value => value.cguid === trElem.getAttribute('rowid'))
if (isSiblingNodes) {
break
}
this.insertAfter(trElem, lastInsertTrElem)
lastInsertTrElem = trElem
}
}
}
} else {
if (selfRow.parentorgnid !== '000000') {
this.restore(wrapperElem, targetTrElem, alternativeTrElem)
this.$message({
type: 'warning',
message: '只能在同级节点移动!'
})
return
}
selfNode.items.splice(selfNode.index, 1)[0]
tableTreeData.unshift(selfRow)
}
this.tableData = [...tableTreeData]
}
})
})
},
findPrevRowOrItsAncestorIndex(row, selfNode) {
let prevRowIndex = -1
selfNode.items.some((value, index) => {
if (value.cguid === row.cguid) {
prevRowIndex = index
return true
} else {
return false
}
})
if (prevRowIndex === -1) {
const parentRow = xe.findTree(this.tableData, r => r.cguid === row.parentorgnid, { children: 'children' }).item
return this.findPrevRowOrItsAncestorIndex(parentRow, selfNode)
} else {
return prevRowIndex
}
},
isDraggedDown(targetTrElem, alternativeTrElem) {
const targetTrElemId = targetTrElem.getAttribute('rowid')
const alternativeTrElemId = alternativeTrElem.getAttribute('rowid')
const treeArray = xe.toTreeArray(this.tableData)
return treeArray.some((value, index) => {
if (value.cguid === targetTrElemId && xe.findIndexOf(treeArray, item => item.cguid === alternativeTrElemId) > index) {
return true
}
})
},
restore(wrapperElem, targetTrElem, alternativeTrElem) {
const insertBefore = this.isDraggedDown(targetTrElem, alternativeTrElem)
if (insertBefore) {
wrapperElem.insertBefore(targetTrElem, alternativeTrElem)
} else {
this.insertAfter(targetTrElem, alternativeTrElem)
}
},
insertAfter(newElement, targetElement) {
var parent = targetElement.parentNode
if (parent.lastChild === targetElement) {
parent.appendChild(newElement)
} else {
parent.insertBefore(newElement, targetElement.nextSibling)
}
}
|