forked from vueuse/vueuse
/
index.ts
165 lines (146 loc) · 4.41 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import type { Arrayable, Fn, MaybeComputedRef } from '@vueuse/shared'
import { isString, noop, tryOnScopeDispose } from '@vueuse/shared'
import { watch } from 'vue-demi'
import type { MaybeElementRef } from '../unrefElement'
import { unrefElement } from '../unrefElement'
import { defaultWindow } from '../_configurable'
interface InferEventTarget<Events> {
addEventListener(event: Events, fn?: any, options?: any): any
removeEventListener(event: Events, fn?: any, options?: any): any
}
export type WindowEventName = keyof WindowEventMap
export type DocumentEventName = keyof DocumentEventMap
export interface GeneralEventListener<E = Event> {
(evt: E): void
}
/**
* Register using addEventListener on mounted, and removeEventListener automatically on unmounted.
*
* Overload 1: Omitted Window target
*
* @see https://vueuse.org/useEventListener
* @param event
* @param listener
* @param options
*/
export function useEventListener<E extends keyof WindowEventMap>(
event: Arrayable<E>,
listener: Arrayable<(this: Window, ev: WindowEventMap[E]) => any>,
options?: boolean | AddEventListenerOptions
): Fn
/**
* Register using addEventListener on mounted, and removeEventListener automatically on unmounted.
*
* Overload 2: Explicitly Window target
*
* @see https://vueuse.org/useEventListener
* @param target
* @param event
* @param listener
* @param options
*/
export function useEventListener<E extends keyof WindowEventMap>(
target: Window,
event: Arrayable<E>,
listener: Arrayable<(this: Window, ev: WindowEventMap[E]) => any>,
options?: boolean | AddEventListenerOptions
): Fn
/**
* Register using addEventListener on mounted, and removeEventListener automatically on unmounted.
*
* Overload 3: Explicitly Document target
*
* @see https://vueuse.org/useEventListener
* @param target
* @param event
* @param listener
* @param options
*/
export function useEventListener<E extends keyof DocumentEventMap>(
target: DocumentOrShadowRoot,
event: Arrayable<E>,
listener: Arrayable<(this: Document, ev: DocumentEventMap[E]) => any>,
options?: boolean | AddEventListenerOptions
): Fn
/**
* Register using addEventListener on mounted, and removeEventListener automatically on unmounted.
*
* Overload 4: Custom event target with event type infer
*
* @see https://vueuse.org/useEventListener
* @param target
* @param event
* @param listener
* @param options
*/
export function useEventListener<Names extends string, EventType = Event>(
target: InferEventTarget<Names>,
event: Arrayable<Names>,
listener: Arrayable<GeneralEventListener<EventType>>,
options?: boolean | AddEventListenerOptions
): Fn
/**
* Register using addEventListener on mounted, and removeEventListener automatically on unmounted.
*
* Overload 5: Custom event target fallback
*
* @see https://vueuse.org/useEventListener
* @param target
* @param event
* @param listener
* @param options
*/
export function useEventListener<EventType = Event>(
target: MaybeComputedRef<EventTarget | null | undefined>,
event: Arrayable<string>,
listener: Arrayable<GeneralEventListener<EventType>>,
options?: boolean | AddEventListenerOptions
): Fn
export function useEventListener(...args: any[]) {
let target: MaybeComputedRef<EventTarget> | undefined
let events: Arrayable<string>
let listeners: Arrayable<Function>
let options: any
if (isString(args[0]) || Array.isArray(args[0])) {
[events, listeners, options] = args
target = defaultWindow
}
else {
[target, events, listeners, options] = args
}
if (!target)
return noop
if (!Array.isArray(events))
events = [events]
if (!Array.isArray(listeners))
listeners = [listeners]
const cleanups: Function[] = []
const cleanup = () => {
cleanups.forEach(fn => fn())
cleanups.length = 0
}
const register = (el: any, event: string, listener: any) => {
el.addEventListener(event, listener, options)
return () => el.removeEventListener(event, listener, options)
}
const stopWatch = watch(
() => unrefElement(target as unknown as MaybeElementRef),
(el) => {
cleanup()
if (!el)
return
cleanups.push(
...(events as string[]).flatMap((event) => {
return (listeners as Function[]).map(listener => register(el, event, listener))
}),
)
},
{ immediate: true, flush: 'post' },
)
const stop = () => {
stopWatch()
cleanup()
}
tryOnScopeDispose(stop)
return stop
}