1
1
import type { MaybeElementRef } from '../unrefElement'
2
2
import type { UseMouseOptions } from '../useMouse'
3
+ import { tryOnMounted } from '@vueuse/shared'
3
4
import { shallowRef , watch } from 'vue'
4
5
import { defaultWindow } from '../_configurable'
5
6
import { unrefElement } from '../unrefElement'
6
7
import { useEventListener } from '../useEventListener'
7
8
import { useMouse } from '../useMouse'
9
+ import { useMutationObserver } from '../useMutationObserver'
10
+ import { useResizeObserver } from '../useResizeObserver'
8
11
9
12
export interface MouseInElementOptions extends UseMouseOptions {
13
+ /**
14
+ * Whether to handle mouse events when the cursor is outside the target element.
15
+ * When enabled, mouse position will continue to be tracked even when outside the element bounds.
16
+ *
17
+ * @default true
18
+ */
10
19
handleOutside ?: boolean
20
+
21
+ /**
22
+ * Listen to window resize event
23
+ *
24
+ * @default true
25
+ */
26
+ windowScroll ?: boolean
27
+
28
+ /**
29
+ * Listen to window scroll event
30
+ *
31
+ * @default true
32
+ */
33
+ windowResize ?: boolean
11
34
}
12
35
13
36
/**
@@ -22,6 +45,8 @@ export function useMouseInElement(
22
45
options : MouseInElementOptions = { } ,
23
46
) {
24
47
const {
48
+ windowResize = true ,
49
+ windowScroll = true ,
25
50
handleOutside = true ,
26
51
window = defaultWindow ,
27
52
} = options
@@ -38,40 +63,67 @@ export function useMouseInElement(
38
63
const elementWidth = shallowRef ( 0 )
39
64
const isOutside = shallowRef ( true )
40
65
41
- let stop = ( ) => { }
66
+ function update ( ) {
67
+ if ( ! window )
68
+ return
69
+
70
+ const el = unrefElement ( targetRef )
71
+ if ( ! el || ! ( el instanceof Element ) )
72
+ return
73
+
74
+ const {
75
+ left,
76
+ top,
77
+ width,
78
+ height,
79
+ } = el . getBoundingClientRect ( )
80
+
81
+ elementPositionX . value = left + ( type === 'page' ? window . pageXOffset : 0 )
82
+ elementPositionY . value = top + ( type === 'page' ? window . pageYOffset : 0 )
83
+ elementHeight . value = height
84
+ elementWidth . value = width
85
+
86
+ const elX = x . value - elementPositionX . value
87
+ const elY = y . value - elementPositionY . value
88
+ isOutside . value = width === 0 || height === 0
89
+ || elX < 0 || elY < 0
90
+ || elX > width || elY > height
91
+
92
+ if ( handleOutside ) {
93
+ elementX . value = elX
94
+ elementY . value = elY
95
+ }
96
+ }
97
+
98
+ const stopFnList : Array < ( ) => void > = [ ]
99
+ function stop ( ) {
100
+ stopFnList . forEach ( fn => fn ( ) )
101
+ stopFnList . length = 0
102
+ }
103
+
104
+ tryOnMounted ( ( ) => {
105
+ update ( )
106
+ } )
42
107
43
108
if ( window ) {
44
- stop = watch (
109
+ const {
110
+ stop : stopResizeObserver ,
111
+ } = useResizeObserver ( targetRef , update )
112
+ const {
113
+ stop : stopMutationObserver ,
114
+ } = useMutationObserver ( targetRef , update , {
115
+ attributeFilter : [ 'style' , 'class' ] ,
116
+ } )
117
+
118
+ const stopWatch = watch (
45
119
[ targetRef , x , y ] ,
46
- ( ) => {
47
- const el = unrefElement ( targetRef )
48
- if ( ! el || ! ( el instanceof Element ) )
49
- return
50
-
51
- const {
52
- left,
53
- top,
54
- width,
55
- height,
56
- } = el . getBoundingClientRect ( )
57
-
58
- elementPositionX . value = left + ( type === 'page' ? window . pageXOffset : 0 )
59
- elementPositionY . value = top + ( type === 'page' ? window . pageYOffset : 0 )
60
- elementHeight . value = height
61
- elementWidth . value = width
62
-
63
- const elX = x . value - elementPositionX . value
64
- const elY = y . value - elementPositionY . value
65
- isOutside . value = width === 0 || height === 0
66
- || elX < 0 || elY < 0
67
- || elX > width || elY > height
68
-
69
- if ( handleOutside || ! isOutside . value ) {
70
- elementX . value = elX
71
- elementY . value = elY
72
- }
73
- } ,
74
- { immediate : true } ,
120
+ update ,
121
+ )
122
+
123
+ stopFnList . push (
124
+ stopResizeObserver ,
125
+ stopMutationObserver ,
126
+ stopWatch ,
75
127
)
76
128
77
129
useEventListener (
@@ -80,6 +132,17 @@ export function useMouseInElement(
80
132
( ) => isOutside . value = true ,
81
133
{ passive : true } ,
82
134
)
135
+
136
+ if ( windowScroll ) {
137
+ stopFnList . push (
138
+ useEventListener ( 'scroll' , update , { capture : true , passive : true } ) ,
139
+ )
140
+ }
141
+ if ( windowResize ) {
142
+ stopFnList . push (
143
+ useEventListener ( 'resize' , update , { passive : true } ) ,
144
+ )
145
+ }
83
146
}
84
147
85
148
return {
0 commit comments