Browse Source

树状数据优化

typings
npmrun 3 years ago
parent
commit
0708c96f00
  1. 47
      packages/components/tree/node.vue
  2. 80
      packages/components/tree/tree.vue
  3. 1
      packages/components/tree/type.ts
  4. 11
      packages/components/tree/util.ts
  5. 2
      packages/playground/src/components/Panel.vue
  6. 41
      packages/playground/src/dev/tree.vue
  7. 8
      packages/theme-chalk/src/tree.scss

47
packages/components/tree/node.vue

@ -1,7 +1,17 @@
<template> <template>
<div class="ps-tree-node component" :class="[{ draging: status === ENiuTreeStatus.DragIng }]"> <div>
<div class="ps-tree-node-wrapper" ref="nodeEL" :draggable="draggable" :onDragstart="onDragstart" <div :style="{ marginLeft: parentLevel * 10 + 'px' }" :class="[
:onDragend="onDragend" :onDrop="onDrop" :onDragover="onDragover" :onDragleave="onDragleave" {
'ps-tree-drag-in':
dataSourceKey != data.key &&
dataSourceKey &&
!isChildOf(data.key, dataSourceKey, list) &&
status === ENiuTreeStatus.DragInner,
},
]"></div>
<div class="ps-tree-node component" :class="[{ draging: status === ENiuTreeStatus.DragIng }]">
<div class="ps-tree-node-wrapper" ref="nodeEL" :draggable="draggable" @dragstart.stop="onDragstart"
@dragend.stop="onDragend" @drop.stop="onDrop" @dragover.stop="onDragover" @dragleave.stop="onDragleave"
@click.stop="emit('click', data)"> @click.stop="emit('click', data)">
<slot :data="data" :deep="level" :dataSourceKey="dataSourceKey" :status="status"> <slot :data="data" :deep="level" :dataSourceKey="dataSourceKey" :status="status">
<div :style="{ <div :style="{
@ -57,6 +67,7 @@
</template> </template>
</div> </div>
</div> </div>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -92,6 +103,12 @@ const props = withDefaults(
level: 0, level: 0,
} }
) )
const parentLevel = computed(()=>{
let level = props.level - 1
return level>=0?level:0
})
const slots = useSlots() const slots = useSlots()
const aa = (fuck: any)=>renderSlot(slots, "default", fuck) const aa = (fuck: any)=>renderSlot(slots, "default", fuck)
@ -160,14 +177,22 @@ function onDragover(event: DragEvent) {
return return
const y = event.offsetY const y = event.offsetY
const h = (event.currentTarget as HTMLDivElement).offsetHeight const h = (event.currentTarget as HTMLDivElement).offsetHeight
if (y < h / 3 && !opts.sort) { if(!opts.sort){
status.value = ENiuTreeStatus.DragUp if (y < h / 3) {
} else if (y <= (h * 2) / 3 && y >= h / 3 && props.data.children) { status.value = ENiuTreeStatus.DragUp
status.value = ENiuTreeStatus.DragIn } else if (y <= (h * 2) / 3 && y >= h / 3 && props.data.children) {
} else if (y > (h * 2) / 3 && !opts.sort) { status.value = ENiuTreeStatus.DragIn
status.value = ENiuTreeStatus.DragDown } else if (y > (h * 2) / 3) {
} else { status.value = ENiuTreeStatus.DragDown
status.value = undefined } else {
status.value = undefined
}
}else{
if (props.data.children) {
status.value = ENiuTreeStatus.DragIn
} else if (!props.data.children && opts.sort) {
status.value = ENiuTreeStatus.DragInner
}
} }
emit('onDragover', props.data.key) emit('onDragover', props.data.key)
} }

80
packages/components/tree/tree.vue

@ -1,8 +1,10 @@
<template> <template>
<div class="ps-tree component"> <div class="ps-tree component" draggable="true" :class="{ aaa: isDrag }" @dragover.prevent="onDragover2"
@dragleave.stop="onDragleave2" @drop.stop="onDrop2">
<template v-for="(item, index) in sortedList" :key="item.key"> <template v-for="(item, index) in sortedList" :key="item.key">
<node @onDragstart="onDragstart" @expand="onExpand" @onDragEnd="onDragEnd" @onDrop="onDrop" :data-source-key="dataSourceKey" <node @onDragstart="onDragstart" @expand="onExpand" @onDragEnd="onDragEnd" @onDrop="onDrop"
:data="item" :list="sortedList" :level="level" @click="(item) => clickNode(item)"> :data-source-key="dataSourceKey" :data="item" :list="sortedList" :level="level"
@click="(item) => clickNode(item)">
<template <template
#default="{ data, deep, dataSourceKey, status }: { data: INiuTreeData, deep: number, dataSourceKey: INiuTreeKey, status: ENiuTreeStatus }"> #default="{ data, deep, dataSourceKey, status }: { data: INiuTreeData, deep: number, dataSourceKey: INiuTreeKey, status: ENiuTreeStatus }">
<slot :data="data" :deep="deep" :dataSourceKey="dataSourceKey" :status="status"></slot> <slot :data="data" :deep="deep" :dataSourceKey="dataSourceKey" :status="status"></slot>
@ -18,18 +20,20 @@ import type { INiuTreeData, INiuTreeKey } from './type'
import { ENiuTreeStatus } from './type' import { ENiuTreeStatus } from './type'
import { import {
findByKey, findByKey,
findByKeyParent,
forEachTree, forEachTree,
insertAfterByKey, insertAfterByKey,
insertBeforeByKey, insertBeforeByKey,
isChild,
isChildOf, isChildOf,
removeByKey, removeByKey,
} from './util' } from './util'
import {betterDirectorySort} from "./better-directory-sort" import { betterDirectorySort } from "./better-directory-sort"
import { computed } from "@vue/reactivity" import { computed } from "@vue/reactivity"
const sortedList = computed(()=>{ const sortedList = computed(() => {
if(props.sort){ if (props.sort) {
return props.list.sort((a, b) => { return props.list.sort((a, b) => {
return betterDirectorySort( return betterDirectorySort(
{ name: a.title, isDirectory: a.isFolder }, { name: a.title, isDirectory: a.isFolder },
@ -40,6 +44,39 @@ const sortedList = computed(()=>{
return props.list return props.list
}) })
const isDrag = ref(false)
function onDragover2() {
if (!props.sort) return
if (!dataSourceKey.value) return
if (!isChild(dataSourceKey.value, props.list)) {
isDrag.value = true
}
}
function onDragleave2() {
if (!props.sort) return
isDrag.value = false
}
async function onDrop2(ev) {
if (!props.sort) return
if (!dataSourceKey.value) return
if (!isDrag.value) return
isDrag.value = false
let data = findByKey(dataSourceKey.value, props.list)
const sourceKey = dataSourceKey.value;
dataSourceKey.value = undefined
if (
data
) {
const isSuccess = (await props.dropFn?.(ENiuTreeStatus.DragIn, data, props.list))
if (isSuccess == undefined || isSuccess) {
removeByKey(sourceKey, props.list)
props.list.push(data)
emit("change")
}
}
}
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
list: INiuTreeData[] list: INiuTreeData[]
@ -48,7 +85,7 @@ const props = withDefaults(
justOpenOne?: boolean justOpenOne?: boolean
sort?: boolean sort?: boolean
level?: number level?: number
dropFn?(status: ENiuTreeStatus, data: INiuTreeData, targetData: INiuTreeData): boolean | Promise<boolean> dropFn?(status: ENiuTreeStatus, data: INiuTreeData, targetDataList: INiuTreeData[]): boolean | Promise<boolean>
}>(), }>(),
{ {
justOpenOne: false, justOpenOne: false,
@ -101,6 +138,29 @@ async function onDrop(key: INiuTreeKey, status?: ENiuTreeStatus) {
const sourceKey = dataSourceKey.value; const sourceKey = dataSourceKey.value;
dataSourceKey.value = undefined dataSourceKey.value = undefined
switch (status) { switch (status) {
case ENiuTreeStatus.DragInner:
const parentData = findByKeyParent(key, props.list)
if (
data &&
targetData &&
sourceKey != key &&
!isChildOf(key, sourceKey, props.list)
) {
const isSuccess = (await props.dropFn?.(status, data, parentData?.children ?? props.list))
if (isSuccess == undefined || isSuccess) {
removeByKey(sourceKey, props.list)
if(parentData){
parentData.children.push(data)
if (props.autoExpand) {
parentData.isExpand = true
}
}else{
props.list.push(data)
}
emit("change")
}
}
break
case ENiuTreeStatus.DragIn: case ENiuTreeStatus.DragIn:
if ( if (
data && data &&
@ -109,7 +169,7 @@ async function onDrop(key: INiuTreeKey, status?: ENiuTreeStatus) {
!isChildOf(key, sourceKey, props.list) && !isChildOf(key, sourceKey, props.list) &&
targetData.children targetData.children
) { ) {
const isSuccess = (await props.dropFn?.(status, data, targetData)) const isSuccess = (await props.dropFn?.(status, data, targetData.children))
if (isSuccess == undefined || isSuccess) { if (isSuccess == undefined || isSuccess) {
removeByKey(sourceKey, props.list) removeByKey(sourceKey, props.list)
targetData.children.push(data) targetData.children.push(data)
@ -128,7 +188,7 @@ async function onDrop(key: INiuTreeKey, status?: ENiuTreeStatus) {
sourceKey != key && sourceKey != key &&
!isChildOf(key, sourceKey, props.list) !isChildOf(key, sourceKey, props.list)
) { ) {
const isSuccess = (await props.dropFn?.(status, data, targetData)) const isSuccess = (await props.dropFn?.(status, data, targetData.children))
if (isSuccess == undefined || isSuccess) { if (isSuccess == undefined || isSuccess) {
removeByKey(sourceKey, props.list) removeByKey(sourceKey, props.list)
insertAfterByKey(key, data, props.list) insertAfterByKey(key, data, props.list)
@ -144,7 +204,7 @@ async function onDrop(key: INiuTreeKey, status?: ENiuTreeStatus) {
sourceKey != key && sourceKey != key &&
!isChildOf(key, sourceKey, props.list) !isChildOf(key, sourceKey, props.list)
) { ) {
const isSuccess = (await props.dropFn?.(status, data, targetData)) const isSuccess = (await props.dropFn?.(status, data, targetData.children))
if (isSuccess == undefined || isSuccess) { if (isSuccess == undefined || isSuccess) {
removeByKey(sourceKey, props.list) removeByKey(sourceKey, props.list)
insertBeforeByKey(key, data, props.list) insertBeforeByKey(key, data, props.list)

1
packages/components/tree/type.ts

@ -27,6 +27,7 @@ export interface INiuTreeData<T = any> {
export enum ENiuTreeStatus { export enum ENiuTreeStatus {
DragUp = 'drag-up', DragUp = 'drag-up',
DragIn = 'drag-in', DragIn = 'drag-in',
DragInner = 'drag-inner',
DragDown = 'drag-down', DragDown = 'drag-down',
DragIng = 'drag-ing', DragIng = 'drag-ing',
} }

11
packages/components/tree/util.ts

@ -59,7 +59,16 @@ export function isChildOf(
-1 -1
) )
} }
export function isChild(
a_key: INiuTreeKey,
treeData: INiuTreeData[]
) {
if (!a_key) return false
return (
treeData.findIndex((i) => i.key === a_key) >
-1
)
}
export function forEachTree(tree: INiuTreeData[], cb: (node: INiuTreeData)=>void) { export function forEachTree(tree: INiuTreeData[], cb: (node: INiuTreeData)=>void) {
tree.forEach(v=>{ tree.forEach(v=>{
cb && cb(v) cb && cb(v)

2
packages/playground/src/components/Panel.vue

@ -8,7 +8,7 @@
{{ desc }} {{ desc }}
</span> </span>
</div> </div>
<div class="flex-1 p-15px"> <div class="flex-1 p-15px min-h-150px">
<slot></slot> <slot></slot>
</div> </div>
</div> </div>

41
packages/playground/src/dev/tree.vue

@ -11,11 +11,34 @@ const list = ref(convertTreeData([
{ {
key: 5, key: 5,
title: "5文件夹", title: "5文件夹",
children: [] children: [
{
key: 2,
title: "ccc"
},
{
key: 3,
title: "bbb"
},
]
}, },
] ]
}, },
{
key: 6,
title: "basdbb"
},
]))
const list2 = ref(convertTreeData([
{ {
key: 1,
title: "aaa",
children: [
{
key: 5,
title: "5文件夹",
children: [
{
key: 2, key: 2,
title: "ccc" title: "ccc"
}, },
@ -23,16 +46,24 @@ const list = ref(convertTreeData([
key: 3, key: 3,
title: "bbb" title: "bbb"
}, },
]
},
]
},
{
key: 6,
title: "basdbb"
},
])) ]))
function onExpand(node: INiuTreeData) { function onExpand(node: INiuTreeData) {
console.log(node); console.log(node);
} }
const dropFn = (status: ENiuTreeStatus, data: INiuTreeData<any>, targetData: INiuTreeData<any>): Promise<boolean> => { const dropFn = (status: ENiuTreeStatus, data: INiuTreeData<any>, list: INiuTreeData<any>[]): Promise<boolean> => {
return new Promise((resolve) => { return new Promise((resolve) => {
setTimeout(() => { // setTimeout(() => {
resolve(true) resolve(true)
}, 2000); // }, 2000);
}) })
} }
</script> </script>
@ -52,7 +83,7 @@ const dropFn = (status: ENiuTreeStatus, data: INiuTreeData<any>, targetData: INi
</ps-tree> </ps-tree>
</Panel> </Panel>
<Panel name="Tree" desc="延迟2000ms执行操作"> <Panel name="Tree" desc="延迟2000ms执行操作">
<ps-tree sort @expand="onExpand" :dropFn="dropFn" :list="list" auto-expand> <ps-tree sort @expand="onExpand" :dropFn="dropFn" :list="list2" auto-expand>
<template #default="{ data, deep }"> <template #default="{ data, deep }">
<div :style="{ <div :style="{
marginLeft: deep * 10 + 'px', marginLeft: deep * 10 + 'px',

8
packages/theme-chalk/src/tree.scss

@ -1,5 +1,11 @@
@import 'common/var.scss'; @import 'common/var.scss';
.ps-tree.component{
height: 100%;
position: relative;
&.aaa{
background-color: $primary-color !important;
}
}
.ps-tree-node.component { .ps-tree-node.component {
position: relative; position: relative;

Loading…
Cancel
Save