Files
workspace/code/g3soft-libs/docs/examples/tree/draggable.vue
T
2026-10-09 17:32:14 +08:00

73 lines
2.3 KiB
Vue

<script setup lang="ts">
// draggable:拖到行的上/下 25% 是「前/后插入」,中间是「放入内部」
// drop 事件里自己重排数据(组件不直接改 treeData)
import { ref } from 'vue'
import { G3Message, G3Tree, type TreeNodeData } from '@g3soft/ui'
const treeData = ref<TreeNodeData[]>([
{ key: '1', title: '第一项' },
{ key: '2', title: '第二项' },
{
key: '3',
title: '第三项(可拖入)',
children: [{ key: '3-1', title: '子项' }],
},
])
function findNode(nodes: TreeNodeData[], key: string): TreeNodeData | null {
for (const node of nodes) {
if (String(node.key) === key) return node
const found = node.children ? findNode(node.children, key) : null
if (found) return found
}
return null
}
function removeNode(nodes: TreeNodeData[], key: string): TreeNodeData | null {
const index = nodes.findIndex((node) => String(node.key) === key)
if (index >= 0) return nodes.splice(index, 1)[0]
for (const node of nodes) {
if (node.children) {
const removed = removeNode(node.children, key)
if (removed) return removed
}
}
return null
}
function onDrop(info: { dragKey: string | number; dropKey: string | number; dropPosition: string }) {
const dragKey = String(info.dragKey)
const dropKey = String(info.dropKey)
const data = treeData.value
const moved = removeNode(data, dragKey)
if (!moved) return
if (info.dropPosition === 'inside') {
const target = findNode(data, dropKey)
if (target) {
target.children = [...(target.children ?? []), moved]
G3Message.success(`已移动到「${target.title}」内部`)
}
} else {
const insert = (nodes: TreeNodeData[]): boolean => {
const index = nodes.findIndex((node) => String(node.key) === dropKey)
if (index >= 0) {
nodes.splice(info.dropPosition === 'before' ? index : index + 1, 0, moved)
return true
}
return nodes.some((node) => (node.children ? insert(node.children) : false))
}
insert(data)
G3Message.success(`已${info.dropPosition === 'before' ? '前移' : '后移'}到「${dropKey}」`)
}
treeData.value = [...data]
}
</script>
<template>
<div style="max-width: 320px">
<G3Tree :tree-data="treeData" draggable default-expand-all block-node @drop="onDrop" />
</div>
</template>