You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

154 lines
5.7 KiB

<template>
<div class="ps-tree-node component" :class="[{ draging: status === ENiuTreeStatus.DragIng }]">
<div class="ps-tree-node-wrapper" ref="nodeEL" :draggable="draggable" :onDragstart="onDragstart"
:onDragend="onDragend" :onDrop="onDrop" :onDragover="onDragover" :onDragleave="onDragleave"
@click.stop="emit('click', data)">
<slot :data="data" :deep="level" :dataSourceKey="dataSourceKey" :status="status">
<div :style="{
marginLeft: level * 10 + 'px',
'position': 'relative',
zIndex: 10
}">
{{ data.title }} - {{ level * 10 + 'px' }}
</div>
<NiuTreeDrag v-bind="props" :status="status" :style="{
marginLeft: level * 10 + 'px',
}"></NiuTreeDrag>
</slot>
</div>
<div class="ps-tree-sub-node" v-if="(opts.justOpen || data.isExpand) && data.children && data.children.length">
<template v-for="(item, index) in data.children" :key="item.key">
<node @onDragstart="(e: INiuTreeKey) => emit('onDragstart', e)"
@onDragend="(e: INiuTreeKey) => emit('onDragend', e)"
@onDrop="(e: INiuTreeKey, s?: ENiuTreeStatus) => emit('onDrop', e, s)"
@onDragover="(e: INiuTreeKey) => emit('onDragover', e)"
@onDragleave="(e: INiuTreeKey) => emit('onDragleave', e)"
@click="(e: INiuTreeData) => emit('click', e)" :data-source-key="dataSourceKey" :data="item"
:list="list" :level="level + 1">
<template
#default="{ data, deep, dataSourceKey, status }: { data: INiuTreeData, deep: number, dataSourceKey: INiuTreeKey, status: ENiuTreeStatus }">
<slot :data="data" :deep="deep" :dataSourceKey="dataSourceKey" :status="status">
<div :style="{
marginLeft: deep * 10 + 'px',
'position': 'relative',
zIndex: 10
}">
{{ data.title }} - {{ deep * 10 + 'px' }}
</div>
<NiuTreeDrag v-bind="props" :status="status" :style="{
marginLeft: deep * 10 + 'px',
}"></NiuTreeDrag>
</slot>
</template>
</node>
</template>
</div>
</div>
</template>
<script lang="ts" setup>
import { isChildOf } from './util'
import NiuTreeDrag from './tree-drag.vue';
import { ENiuTreeStatus, INiuTreeData, INiuTreeKey } from './type';
const props = withDefaults(
defineProps<{
data: INiuTreeData
list: INiuTreeData[]
dataSourceKey?: INiuTreeKey
level?: number
}>(),
{
level: 0,
}
)
const opts = inject("tree:opts", {
justOpen: false
})
const emit = defineEmits<{
(e: 'click', data: INiuTreeData): void
(e: 'onDragstart', key: INiuTreeKey): void
(e: 'onDragend', key: INiuTreeKey): void
(e: 'onDrop', key: INiuTreeKey, status?: ENiuTreeStatus): void
(e: 'onDragover', key: INiuTreeKey): void
(e: 'onDragleave', key: INiuTreeKey): void
}>()
const draggable = ref(true)
const status = ref<ENiuTreeStatus>()
const nodeEL = ref<HTMLDivElement>()
provide("draggable", draggable)
function onDragstart(event: DragEvent) {
// 开始拖拽
if (event.dataTransfer) {
event.dataTransfer.dropEffect = 'move'
event.dataTransfer.effectAllowed = 'move'
if (nodeEL.value) {
let clone = nodeEL.value.cloneNode(true) as HTMLDivElement
clone.id = 'dragging_node'
clone.style.display = 'inline-block'
clone.style.position = 'absolute'
clone.style.zIndex = '100000'
clone.style.width = '100px'
clone.style.top = '-100000px'
document.body.append(clone)
event.dataTransfer.setDragImage(clone, -4, -4)
}
emit('onDragstart', props.data.key)
status.value = ENiuTreeStatus.DragIng
}
}
function onDragend() {
// 结束拖拽
let clone = document.getElementById('dragging_node')
clone?.remove()
status.value = undefined
emit('onDragend', props.data.key)
}
function onDrop(e: DragEvent) {
e.preventDefault()
emit('onDrop', props.data.key, status.value)
status.value = undefined
}
function onDragover(event: DragEvent) {
event.preventDefault()
if (!props.dataSourceKey) return
if (props.dataSourceKey === props.data.key) return
if (
props.dataSourceKey &&
isChildOf(props.data.key, props.dataSourceKey, props.list)
)
return
const y = event.offsetY
const h = (event.currentTarget as HTMLDivElement).offsetHeight
if (y < h / 3) {
status.value = ENiuTreeStatus.DragUp
} else if (y <= (h * 2) / 3 && y >= h / 3 && props.data.children) {
status.value = ENiuTreeStatus.DragIn
} else if (y > (h * 2) / 3) {
status.value = ENiuTreeStatus.DragDown
} else {
status.value = undefined
}
emit('onDragover', props.data.key)
}
function onDragleave() {
if (!props.dataSourceKey) return
if (props.dataSourceKey === props.data.key) return
if (
props.dataSourceKey &&
isChildOf(props.data.key, props.dataSourceKey, props.list)
)
return
// 拖拽离开元素上
status.value = undefined
emit('onDragleave', props.data.key)
}
</script>
<script lang="ts">
import { defineComponent, inject, ref, provide } from 'vue'
export default defineComponent({
name: 'ps-tree-node',
})
</script>