refactor(components): [tree] improve emit to get type hints (#22526)

* refactor(components): [tree] improve emit to get type hints

* chore: update

* fix: update

* chore: revert example

* docs: update type

Co-authored-by: Dsaquel <291874700n@gmail.com>

* chore: rename event

Co-authored-by: btea <2356281422@qq.com>

---------

Co-authored-by: Dsaquel <291874700n@gmail.com>
Co-authored-by: btea <2356281422@qq.com>
This commit is contained in:
Zhong
2025-10-20 14:43:47 +08:00
committed by GitHub
parent b917fafccc
commit a65d218e22
7 changed files with 91 additions and 39 deletions

View File

@@ -19,46 +19,37 @@
<script lang="ts" setup>
import type {
AllowDropType,
DragEvents,
NodeDropType,
RenderContentContext,
} from 'element-plus'
type Node = RenderContentContext['node']
const handleDragStart = (node: Node, ev: DragEvents) => {
const handleDragStart = (node: Node, ev: DragEvent) => {
console.log('drag start', node)
}
const handleDragEnter = (
draggingNode: Node,
dropNode: Node,
ev: DragEvents
) => {
const handleDragEnter = (draggingNode: Node, dropNode: Node, ev: DragEvent) => {
console.log('tree drag enter:', dropNode.label)
}
const handleDragLeave = (
draggingNode: Node,
dropNode: Node,
ev: DragEvents
) => {
const handleDragLeave = (draggingNode: Node, dropNode: Node, ev: DragEvent) => {
console.log('tree drag leave:', dropNode.label)
}
const handleDragOver = (draggingNode: Node, dropNode: Node, ev: DragEvents) => {
const handleDragOver = (draggingNode: Node, dropNode: Node, ev: DragEvent) => {
console.log('tree drag over:', dropNode.label)
}
const handleDragEnd = (
draggingNode: Node,
dropNode: Node,
dropNode: Node | null,
dropType: NodeDropType,
ev: DragEvents
ev: DragEvent
) => {
console.log('tree drag end:', dropNode && dropNode.label, dropType)
}
const handleDrop = (
draggingNode: Node,
dropNode: Node,
dropType: NodeDropType,
ev: DragEvents
dropType: Exclude<NodeDropType, 'none'>,
ev: DragEvent
) => {
console.log('tree drop:', dropNode.label, dropType)
}

View File

@@ -10,3 +10,4 @@ export default ElTree
export * from './src/tree.type'
export * from './src/instance'
export * from './src/tokens'
export * from './src/tree'

View File

@@ -11,6 +11,7 @@ import type {
} from '../tree.type'
import type TreeStore from './tree-store'
import type Node from './node'
import type { treeEmits } from '../tree'
interface TreeNode {
node: Node
@@ -27,7 +28,7 @@ interface Props {
allowDrag?: AllowDragFunction
allowDrop?: AllowDropFunction
}
ctx: SetupContext<string[]>
ctx: SetupContext<typeof treeEmits>
el$: Ref<HTMLElement | null>
dropIndicator$: Ref<HTMLElement | null>
store: Ref<TreeStore>
@@ -242,15 +243,21 @@ export function useDragNodeHandler({
'node-drag-end',
draggingNode.node,
dropNode.node,
dropType,
dropType!,
event
)
if (dropType !== 'none') {
ctx.emit('node-drop', draggingNode.node, dropNode.node, dropType, event)
ctx.emit(
'node-drop',
draggingNode.node,
dropNode.node,
dropType!,
event
)
}
}
if (draggingNode && !dropNode) {
ctx.emit('node-drag-end', draggingNode.node, null, dropType, event)
ctx.emit('node-drag-end', draggingNode.node, null, dropType!, event)
}
dragState.value.showDropIndicator = false

View File

@@ -1,5 +1,5 @@
import type { SetupContext } from 'vue'
import type Node from './node'
import type { TreeEmits } from '../tree'
import type { RootTreeType, TreeKey, TreeNodeData } from '../tree.type'
export const NODE_KEY = '$treeNodeId'
@@ -22,7 +22,7 @@ export const getNodeKey = (key: TreeKey | undefined, data: TreeNodeData) =>
export const handleCurrentChange = (
store: RootTreeType['store'],
emit: SetupContext['emit'],
emit: TreeEmits,
setCurrent: () => void
) => {
const preCurrentNode = store.value.currentNode

View File

@@ -0,0 +1,58 @@
import { isBoolean } from '@element-plus/utils'
import type { ComponentInternalInstance } from 'vue'
import type { EmitFn } from '@element-plus/utils'
import type Node from './model/node'
import type { CheckedInfo, NodeDropType } from './tree.type'
/* eslint-disable @typescript-eslint/no-unused-vars */
export const treeEmits = {
'check-change': (data: any, checked: boolean, indeterminate: boolean) =>
data && isBoolean(checked) && isBoolean(indeterminate),
'current-change': (data: any | null, node: Node | null) => true,
'node-click': (
data: any,
node: Node,
nodeInstance: ComponentInternalInstance | null,
evt: MouseEvent
) => data && node && evt instanceof Event,
'node-contextmenu': (
evt: Event,
data: any,
node: Node,
nodeInstance: ComponentInternalInstance | null
) => evt instanceof Event && data && node,
'node-collapse': (
data: any,
node: Node,
nodeInstance: ComponentInternalInstance | null
) => data && node,
'node-expand': (
data: any,
node: Node,
nodeInstance: ComponentInternalInstance | null
) => data && node,
check: (data: any, checkedInfo: CheckedInfo) => data && checkedInfo,
'node-drag-start': (node: Node, evt: DragEvent) => node && evt,
'node-drag-end': (
draggingNode: Node,
dropNode: Node | null,
dropType: NodeDropType,
evt: DragEvent
) => draggingNode && evt,
'node-drop': (
draggingNode: Node,
dropNode: Node,
dropType: Exclude<NodeDropType, 'none'>,
evt: DragEvent
) => draggingNode && dropNode && evt,
'node-drag-leave': (draggingNode: Node, oldDropNode: Node, evt: DragEvent) =>
draggingNode && oldDropNode && evt,
'node-drag-enter': (draggingNode: Node, dropNode: Node, evt: DragEvent) =>
draggingNode && dropNode && evt,
'node-drag-over': (draggingNode: Node, dropNode: Node, evt: DragEvent) =>
draggingNode && dropNode && evt,
}
/* eslint-enable @typescript-eslint/no-unused-vars */
export type TreeEmits = EmitFn<typeof treeEmits>

View File

@@ -8,9 +8,10 @@ import type {
} from 'vue'
import type Node from './model/node'
import type TreeStore from './model/tree-store'
import type { treeEmits } from './tree'
export interface RootTreeType {
ctx: SetupContext<any>
ctx: SetupContext<typeof treeEmits>
props: TreeComponentProps
store: Ref<TreeStore>
root: Ref<Node>
@@ -128,3 +129,10 @@ export interface TreeComponentProps {
export type NodeDropType = 'before' | 'after' | 'inner' | 'none'
export type { DragEvents } from './model/useDragNode'
export interface CheckedInfo {
checkedKeys: TreeKey[]
checkedNodes: TreeData
halfCheckedKeys: TreeKey[]
halfCheckedNodes: TreeData
}

View File

@@ -58,6 +58,7 @@ import { useDragNodeHandler } from './model/useDragNode'
import { useKeydown } from './model/useKeydown'
import { ROOT_TREE_INJECTION_KEY } from './tokens'
import { isEqual } from 'lodash-unified'
import { treeEmits } from './tree'
import type Node from './model/node'
import type { ComponentInternalInstance, PropType } from 'vue'
@@ -146,21 +147,7 @@ export default defineComponent({
type: iconPropType,
},
},
emits: [
'check-change',
'current-change',
'node-click',
'node-contextmenu',
'node-collapse',
'node-expand',
'check',
'node-drag-start',
'node-drag-end',
'node-drop',
'node-drag-leave',
'node-drag-enter',
'node-drag-over',
] as string[],
emits: treeEmits,
setup(props, ctx) {
const { t } = useLocale()
const ns = useNamespace('tree')