Skip to content

Commit 04af98c

Browse files
Codfisherbgm-cod
andauthored
fix(useMouseInElement): fixing the issue where target element updates were not considered. (#4782)
Co-authored-by: bgm.cod <bgm.codfish@gmail.com>
1 parent 135d507 commit 04af98c

File tree

1 file changed

+94
-31
lines changed

1 file changed

+94
-31
lines changed

packages/core/useMouseInElement/index.ts

Lines changed: 94 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,36 @@
11
import type { MaybeElementRef } from '../unrefElement'
22
import type { UseMouseOptions } from '../useMouse'
3+
import { tryOnMounted } from '@vueuse/shared'
34
import { shallowRef, watch } from 'vue'
45
import { defaultWindow } from '../_configurable'
56
import { unrefElement } from '../unrefElement'
67
import { useEventListener } from '../useEventListener'
78
import { useMouse } from '../useMouse'
9+
import { useMutationObserver } from '../useMutationObserver'
10+
import { useResizeObserver } from '../useResizeObserver'
811

912
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+
*/
1019
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
1134
}
1235

1336
/**
@@ -22,6 +45,8 @@ export function useMouseInElement(
2245
options: MouseInElementOptions = {},
2346
) {
2447
const {
48+
windowResize = true,
49+
windowScroll = true,
2550
handleOutside = true,
2651
window = defaultWindow,
2752
} = options
@@ -38,40 +63,67 @@ export function useMouseInElement(
3863
const elementWidth = shallowRef(0)
3964
const isOutside = shallowRef(true)
4065

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+
})
42107

43108
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(
45119
[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,
75127
)
76128

77129
useEventListener(
@@ -80,6 +132,17 @@ export function useMouseInElement(
80132
() => isOutside.value = true,
81133
{ passive: true },
82134
)
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+
}
83146
}
84147

85148
return {

0 commit comments

Comments
 (0)