11import { reactive , computed , toRaw } from 'vue'
2+ import type { ComputedRef } from 'vue'
3+ import type { PositionType } from '../container'
24import { useMultiSelect } from './useMultiSelect'
35import { useCanvas } from '@opentiny/tiny-engine-meta-register'
46import { NODE_TAG , NODE_UID } from '../../../common'
@@ -19,13 +21,66 @@ import {
1921 getDocument
2022} from '../container'
2123
22- const initialMultiDragState = {
24+ interface Position {
25+ x : number
26+ y : number
27+ }
28+
29+ interface Offset {
30+ offsetX : number
31+ offsetY : number
32+ initialX : number
33+ initialY : number
34+ }
35+
36+ interface NodeSchema {
37+ id : string
38+ componentName : string
39+ children ?: NodeSchema [ ]
40+ [ key : string ] : any
41+ }
42+
43+ interface MultiDragState {
44+ keydown : boolean
45+ draging : boolean
46+ dragStarted : boolean
47+ initialMousePos : Position | null
48+ nodes : NodeSchema [ ]
49+ offsets : Map < string , Offset >
50+ mouse : Position | null
51+ position : PositionType | null
52+ targetNodeId : string | null
53+ }
54+
55+ interface SelectState {
56+ id : string
57+ componentName : string
58+ schema : NodeSchema
59+ top ?: number
60+ left ?: number
61+ width ?: number
62+ height ?: number
63+ doc ?: Document
64+ [ key : string ] : any
65+ }
66+
67+ interface InsertOperation {
68+ sourceId : string
69+ targetNodeData : {
70+ parent : NodeSchema | null
71+ node : NodeSchema
72+ data : NodeSchema
73+ }
74+ position : PositionType
75+ }
76+
77+ const initialMultiDragState : MultiDragState = {
2378 keydown : false ,
2479 draging : false ,
2580 dragStarted : false , // 标记是否已经开始拖拽
2681 initialMousePos : null , // 初始鼠标位置
2782 nodes : [ ] , // 存储被拖拽的多个节点信息
28- offsets : new Map ( ) , // 存储每个节点的偏移量
83+ offsets : new Map < string , Offset > ( ) , // 存储每个节点的偏移量
2984 mouse : null , // 鼠标位置
3085 position : null , // 放置位置
3186 targetNodeId : null // 当前点击的节点ID
@@ -35,16 +90,17 @@ const initialMultiDragState = {
3590const DRAG_THRESHOLD = 5
3691
3792export const useMultiDrag = ( ) => {
38- const multiDragState = reactive ( { ...initialMultiDragState } )
39- const { multiSelectedStates, multiStateLength } = useMultiSelect ( )
93+ const multiDragState = reactive < MultiDragState > ( { ...initialMultiDragState } )
94+ const { multiSelectedStates } = useMultiSelect ( )
95+ const multiStateLength = computed < number > ( ( ) => ( multiSelectedStates . value as SelectState [ ] ) . length )
4096
4197 // 准备拖拽 - 仅记录初始状态,不立即开始拖拽
42- const startMultiDrag = ( event , element ) => {
98+ const startMultiDrag = ( event : MouseEvent , element : HTMLElement ) : boolean => {
4399 if ( multiStateLength . value <= 1 ) return false
44100
45101 // 检查点击的元素是否是已选中的节点之一
46102 const clickedNodeId = element ?. getAttribute ( NODE_UID )
47- if ( ! clickedNodeId || ! multiSelectedStates . value . some ( ( state ) => state . id === clickedNodeId ) ) {
103+ if ( ! clickedNodeId || ! ( multiSelectedStates . value as SelectState [ ] ) . some ( ( state ) => state . id === clickedNodeId ) ) {
48104 return false
49105 }
50106
@@ -54,10 +110,10 @@ export const useMultiDrag = () => {
54110 multiDragState . draging = false
55111 multiDragState . initialMousePos = { x : clientX , y : clientY }
56112 multiDragState . targetNodeId = clickedNodeId
57- multiDragState . nodes = toRaw ( multiSelectedStates . value ) . map ( ( state ) => state . schema )
113+ multiDragState . nodes = toRaw ( multiSelectedStates . value as SelectState [ ] ) . map ( ( state ) => state . schema )
58114
59115 // 计算每个节点相对于鼠标的偏移量
60- multiSelectedStates . value . forEach ( ( state ) => {
116+ ; ( multiSelectedStates . value as SelectState [ ] ) . forEach ( ( state ) => {
61117 const elem = querySelectById ( state . id )
62118 if ( elem ) {
63119 const { x, y } = elem . getBoundingClientRect ( )
@@ -74,7 +130,11 @@ export const useMultiDrag = () => {
74130 }
75131
76132 // 计算放置位置
77- const calculateDropPosition = ( event , rect , configure ) => {
133+ const calculateDropPosition = (
134+ event : MouseEvent ,
135+ rect : DOMRect ,
136+ configure : { isContainer ?: boolean } | null
137+ ) : PositionType => {
78138 const { clientX : mouseX , clientY : mouseY } = event
79139 // 参考单选节点的实现,使用更精确的计算方式
80140 const yAbs = Math . min ( 20 , rect . height / 3 )
@@ -99,15 +159,20 @@ export const useMultiDrag = () => {
99159 }
100160
101161 // 计算鼠标移动距离
102- const calculateDistance = ( pos1 , pos2 ) => {
162+ const calculateDistance = ( pos1 : Position | null , pos2 : Position | null ) : number => {
103163 if ( ! pos1 || ! pos2 ) return 0
104164 const dx = pos1 . x - pos2 . x
105165 const dy = pos1 . y - pos2 . y
106166 return Math . sqrt ( dx * dx + dy * dy )
107167 }
108168
109169 // 检查是否允许放置
110- const checkAllowInsert = ( configure , nodes , targetId , position ) => {
170+ const checkAllowInsert = (
171+ configure : { isContainer ?: boolean } | null ,
172+ nodes : NodeSchema [ ] ,
173+ targetId : string ,
174+ position : PositionType
175+ ) : boolean => {
111176 // 如果没有配置,不允许放置
112177 if ( ! configure ) return false
113178
@@ -183,11 +248,11 @@ export const useMultiDrag = () => {
183248 }
184249
185250 // 拖拽移动
186- const moveMultiDrag = ( event ) => {
251+ const moveMultiDrag = ( event : MouseEvent ) : boolean => {
187252 if ( ! multiDragState . keydown || multiStateLength . value <= 1 ) return false
188253
189254 const { clientX, clientY } = event
190- const currentMousePos = { x : clientX , y : clientY }
255+ const currentMousePos : Position = { x : clientX , y : clientY }
191256
192257 // 如果拖拽还未开始,检查是否超过阈值
193258 if ( ! multiDragState . dragStarted ) {
@@ -217,7 +282,7 @@ export const useMultiDrag = () => {
217282 return false
218283 }
219284
220- const targetElement = getElement ( event . target )
285+ const targetElement = getElement ( event . target as HTMLElement )
221286
222287 // 特殊处理:如果没有找到目标元素,检查是否是body元素或其直接子元素
223288 if ( ! targetElement ) {
@@ -226,7 +291,11 @@ export const useMultiDrag = () => {
226291 const body = doc . body
227292
228293 // 如果鼠标在body区域内,则视为拖拽到body
229- if ( event . target === body || event . target . parentElement === body || event . target === doc . documentElement ) {
294+ if (
295+ event . target === body ||
296+ ( event . target as HTMLElement ) . parentElement === body ||
297+ event . target === doc . documentElement
298+ ) {
230299 // 获取body中的所有顶级节点
231300 const { getSchema } = useCanvas ( )
232301 const bodySchema = getSchema ( )
@@ -252,9 +321,9 @@ export const useMultiDrag = () => {
252321 const { clientY } = event
253322
254323 // 遍历body的直接子节点,找到最接近鼠标位置的节点
255- let closestNode = null
324+ let closestNode : HTMLElement | null = null
256325 let closestDistance = Infinity
257- let position = POSITION . IN // 默认放置到body内部
326+ let position : PositionType = POSITION . IN // 默认放置到body内部
258327
259328 for ( const childSchema of bodyChildren ) {
260329 const childElement = querySelectById ( childSchema . id )
@@ -283,7 +352,7 @@ export const useMultiDrag = () => {
283352 const rect = closestNode . getBoundingClientRect ( )
284353
285354 // 检查是否允许放置
286- const isForbidden = ! checkAllowInsert ( configure , multiDragState . nodes , nodeId , position )
355+ const isForbidden = ! checkAllowInsert ( configure , multiDragState . nodes , nodeId ! , position )
287356
288357 // 更新lineState
289358 Object . assign ( lineState , {
@@ -341,7 +410,7 @@ export const useMultiDrag = () => {
341410 if ( parent ) {
342411 // 根据放置位置调整目标节点
343412 const children = parent . children || [ ]
344- const targetIndex = children . findIndex ( ( child ) => child . id === targetId )
413+ const targetIndex = children . findIndex ( ( child : NodeSchema ) => child . id === targetId )
345414
346415 // 如果是放置到节点下方,使用下一个兄弟节点作为目标
347416 if ( ( position === POSITION . BOTTOM || position === POSITION . RIGHT ) && targetIndex < children . length - 1 ) {
@@ -454,7 +523,7 @@ export const useMultiDrag = () => {
454523 }
455524
456525 // 结束拖拽
457- const endMultiDrag = ( ) => {
526+ const endMultiDrag = ( ) : boolean => {
458527 // 只有真正开始拖拽后才处理放置逻辑
459528 if ( ! multiDragState . draging || ! multiDragState . dragStarted || multiStateLength . value <= 1 ) {
460529 // 重置状态
@@ -475,7 +544,7 @@ export const useMultiDrag = () => {
475544
476545 if ( finalTargetNode ) {
477546 // 创建一个操作批次,以便能够一次性添加历史记录
478- const operations = [ ]
547+ const operations : InsertOperation [ ] = [ ]
479548
480549 // 收集要移动的节点ID,用于后续检查
481550 const movingNodeIds = multiDragState . nodes . map ( ( node ) => node . id )
@@ -512,7 +581,7 @@ export const useMultiDrag = () => {
512581 operations . push ( {
513582 sourceId,
514583 targetNodeData,
515- position
584+ position : position as PositionType
516585 } )
517586 } )
518587
@@ -560,7 +629,7 @@ export const useMultiDrag = () => {
560629 // 延迟执行,确保DOM已更新
561630 setTimeout ( ( ) => {
562631 // 重建多选状态
563- const newMultiSelection = [ ]
632+ const newMultiSelection : SelectState [ ] = [ ]
564633
565634 // 收集所有操作后的节点ID
566635 const newNodeIds = operations . map ( ( op ) => op . targetNodeData . data . id )
@@ -572,9 +641,9 @@ export const useMultiDrag = () => {
572641 const { node } = useCanvas ( ) . getNodeWithParentById ( nodeId ) || { }
573642 if ( ! node ) return
574643
575- const state = {
644+ const state : SelectState = {
576645 id : nodeId ,
577- componentName : element . getAttribute ( NODE_TAG ) ,
646+ componentName : element . getAttribute ( NODE_TAG ) || '' ,
578647 schema : node
579648 }
580649
@@ -614,12 +683,12 @@ export const useMultiDrag = () => {
614683 }
615684
616685 // 判断是否处于多选拖拽状态
617- const isMultiDragging = ( ) => {
686+ const isMultiDragging = ( ) : boolean => {
618687 return multiDragState . draging && multiDragState . dragStarted && multiStateLength . value > 1
619688 }
620689
621690 // 获取多选拖拽的位置描述
622- const getMultiDragPositionText = computed ( ( ) => {
691+ const getMultiDragPositionText : ComputedRef < string > = computed ( ( ) => {
623692 if ( ! isMultiDragging ( ) ) return ''
624693
625694 const { position, forbidden, id } = lineState
@@ -640,15 +709,15 @@ export const useMultiDrag = () => {
640709 }
641710
642711 switch ( position ) {
643- case 'top' :
712+ case POSITION . TOP :
644713 return `放置到 ${ targetComponentName || '目标节点' } 上方`
645- case 'bottom' :
714+ case POSITION . BOTTOM :
646715 return `放置到 ${ targetComponentName || '目标节点' } 下方`
647- case 'left' :
716+ case POSITION . LEFT :
648717 return `放置到 ${ targetComponentName || '目标节点' } 左侧`
649- case 'right' :
718+ case POSITION . RIGHT :
650719 return `放置到 ${ targetComponentName || '目标节点' } 右侧`
651- case 'in' :
720+ case POSITION . IN :
652721 return `放置到 ${ targetComponentName || '容器' } 内部`
653722 default :
654723 return ''
0 commit comments