11import { onUnmounted } from 'vue' ;
22
3- const traversalTabNavs = ( tabNavs : HTMLCollection , fn : { ( itemNode : any ) : void ; ( tabNav : HTMLDivElement ) : void } ) => {
4- for ( const itemNode of tabNavs ) {
5- if ( itemNode . getAttribute ( 'draggable' ) ) {
6- fn ( itemNode ) ;
7- }
8- }
3+ const traversalTabNavs = ( tabNavs : HTMLCollection , fn : ( tabNav : HTMLDivElement ) => void ) => {
4+ Array . from ( tabNavs )
5+ . filter ( ( node ) : node is HTMLDivElement => node instanceof HTMLDivElement && ! ! node . getAttribute ( 'draggable' ) )
6+ . forEach ( fn ) ;
97} ;
108
11- const handleTarget = ( target : EventTarget , tabNavs : HTMLCollection ) : any => {
12- let resultTarget ;
9+ const handleTarget = ( target : EventTarget , tabNavs : HTMLCollection ) : HTMLDivElement | undefined => {
10+ let resultTarget : HTMLDivElement | undefined ;
11+
1312 traversalTabNavs ( tabNavs , ( itemNode ) => {
14- if ( itemNode . contains ( target ) ) {
13+ if ( target instanceof Node && itemNode . contains ( target ) ) {
1514 resultTarget = itemNode ;
1615 }
1716 } ) ;
17+
1818 return resultTarget ;
1919} ;
2020
2121export function useDragSort ( props : any ) {
22- let navsWrap : HTMLDivElement = null ;
22+ let navsWrap : HTMLDivElement | null = null ;
2323
2424 // 获取当前正在拖动的tabNav节点
2525 let dragged : HTMLDivElement ;
@@ -32,22 +32,47 @@ export function useDragSort(props: any) {
3232 dragged = target ;
3333 // 使其半透明
3434 target . style . opacity = '0.5' ;
35+
36+ // 指定允许的拖拽操作为 move,且兼容 Firefox(需要 setData)
37+ const dt = event . dataTransfer ;
38+ if ( dt ) {
39+ dt . effectAllowed = 'copy' ;
40+ try {
41+ dt . setData ( 'text/plain' , '' ) ;
42+ } catch ( e ) {
43+ // 某些环境下可能抛错,忽略
44+ }
45+ }
3546 } ;
47+
3648 const dragend = ( event : DragEvent ) => {
3749 // 重置透明度
3850 ( event . target as HTMLDivElement ) . style . opacity = '' ;
3951 } ;
4052 /* 放置目标元素时触发事件 */
4153 const dragover = ( event : DragEvent ) => {
42- // 阻止默认动作以启用drop
43- event . preventDefault ( ) ;
54+ if ( ! navsWrap ) return ;
55+ const target = handleTarget ( event . target , navsWrap . children ) ;
56+ const dt = event . dataTransfer ;
57+ if ( dt ) {
58+ // 不可放置目标显示禁止状态
59+ dt . dropEffect = target ?. draggable ? 'copy' : 'none' ;
60+ }
61+ if ( target ?. draggable ) {
62+ // 阻止默认动作以启用drop
63+ event . preventDefault ( ) ;
64+ }
4465 } ;
4566 // 当可拖动的元素进入可放置的目标时
4667 const dragenter = ( event : DragEvent ) => {
4768 // 高亮目标节点
4869 const target = handleTarget ( event . target , navsWrap . children ) ;
4970 if ( target && target !== dragged && target . draggable ) {
50- target . firstChild . style . outline = '1px dashed #0052d9' ;
71+ const { firstChild } = target ;
72+ if ( firstChild instanceof HTMLElement ) {
73+ const newStyle = { outline : '1px dashed #0052d9' } ;
74+ Object . assign ( firstChild . style , newStyle ) ;
75+ }
5176 // 进入的节点全部记录下来
5277 if ( ! enterTargets . includes ( target ) ) {
5378 enterTargets . push ( target ) ;
@@ -72,8 +97,12 @@ export function useDragSort(props: any) {
7297 event . preventDefault ( ) ;
7398
7499 traversalTabNavs ( navsWrap . children , ( tabNav ) => {
75- tabNav . firstChild . style . outline = 'none' ;
100+ const firstChild = tabNav . firstChild as HTMLElement ;
101+ if ( firstChild ) {
102+ firstChild . style . outline = 'none' ;
103+ }
76104 } ) ;
105+
77106 // 将拖动的元素到所选择的放置目标节点中
78107 let target = handleTarget ( event . target , navsWrap . children ) ;
79108 if ( target && target . parentNode !== dragged && target . draggable ) {
@@ -82,7 +111,7 @@ export function useDragSort(props: any) {
82111 // 获取放入元素index
83112 const targetIndex = [ ] . indexOf . call ( navsWrap . children , target ) ;
84113 if ( targetIndex > dragIndex ) {
85- target = navsWrap . children [ targetIndex + 1 ] ;
114+ target = navsWrap . children [ targetIndex + 1 ] as HTMLDivElement | null ;
86115 }
87116
88117 // 当props.theme === "normal" 会多出一个指示条为第一个dom节点,所以需要减1
0 commit comments