Skip to content

Commit

Permalink
feat(useEventListener): support reactive options
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Feb 18, 2023
1 parent 73e3a7d commit 103d6c0
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 13 deletions.
26 changes: 24 additions & 2 deletions packages/core/useEventListener/index.test.ts
Expand Up @@ -184,7 +184,7 @@ describe('useEventListener', () => {

function testTarget(useTarget: boolean) {
it(`should ${getTargetName(useTarget)} listen event`, async () => {
// @ts-expect-error mock different args
// @ts-expect-error mock different args
const stop = useEventListener(...getArgs(useTarget))

trigger(useTarget)
Expand All @@ -195,7 +195,7 @@ describe('useEventListener', () => {
})

it(`should ${getTargetName(useTarget)} manually stop listening event`, async () => {
// @ts-expect-error mock different args
// @ts-expect-error mock different args
const stop = useEventListener(...getArgs(useTarget))

stop()
Expand Down Expand Up @@ -227,4 +227,26 @@ describe('useEventListener', () => {
testTarget(false)
testTarget(true)
})

it('should auto re-register', async () => {
const target = ref()
const listener = vi.fn()
const options = ref<any>(false)
useEventListener(target, 'click', listener, options)

const el = document.createElement('div')
const addSpy = vi.spyOn(el, 'addEventListener')
const removeSpy = vi.spyOn(el, 'removeEventListener')
target.value = el
await nextTick()
expect(addSpy).toHaveBeenCalledTimes(1)
expect(addSpy).toHaveBeenLastCalledWith('click', listener, false)
expect(removeSpy).toHaveBeenCalledTimes(0)

options.value = true
await nextTick()
expect(addSpy).toHaveBeenCalledTimes(2)
expect(addSpy).toHaveBeenLastCalledWith('click', listener, true)
expect(removeSpy).toHaveBeenCalledTimes(1)
})
})
22 changes: 11 additions & 11 deletions packages/core/useEventListener/index.ts
@@ -1,5 +1,5 @@
import type { Arrayable, Fn, MaybeComputedRef } from '@vueuse/shared'
import { isString, noop, tryOnScopeDispose } from '@vueuse/shared'
import { isString, noop, resolveUnref, tryOnScopeDispose } from '@vueuse/shared'
import { watch } from 'vue-demi'
import type { MaybeElementRef } from '../unrefElement'
import { unrefElement } from '../unrefElement'
Expand Down Expand Up @@ -30,7 +30,7 @@ export interface GeneralEventListener<E = Event> {
export function useEventListener<E extends keyof WindowEventMap>(
event: Arrayable<E>,
listener: Arrayable<(this: Window, ev: WindowEventMap[E]) => any>,
options?: boolean | AddEventListenerOptions
options?: MaybeComputedRef<boolean | AddEventListenerOptions>
): Fn

/**
Expand All @@ -48,7 +48,7 @@ export function useEventListener<E extends keyof WindowEventMap>(
target: Window,
event: Arrayable<E>,
listener: Arrayable<(this: Window, ev: WindowEventMap[E]) => any>,
options?: boolean | AddEventListenerOptions
options?: MaybeComputedRef<boolean | AddEventListenerOptions>
): Fn

/**
Expand All @@ -66,7 +66,7 @@ export function useEventListener<E extends keyof DocumentEventMap>(
target: DocumentOrShadowRoot,
event: Arrayable<E>,
listener: Arrayable<(this: Document, ev: DocumentEventMap[E]) => any>,
options?: boolean | AddEventListenerOptions
options?: MaybeComputedRef<boolean | AddEventListenerOptions>
): Fn

/**
Expand All @@ -84,7 +84,7 @@ export function useEventListener<Names extends string, EventType = Event>(
target: InferEventTarget<Names>,
event: Arrayable<Names>,
listener: Arrayable<GeneralEventListener<EventType>>,
options?: boolean | AddEventListenerOptions
options?: MaybeComputedRef<boolean | AddEventListenerOptions>
): Fn

/**
Expand All @@ -102,14 +102,14 @@ export function useEventListener<EventType = Event>(
target: MaybeComputedRef<EventTarget | null | undefined>,
event: Arrayable<string>,
listener: Arrayable<GeneralEventListener<EventType>>,
options?: boolean | AddEventListenerOptions
options?: MaybeComputedRef<boolean | AddEventListenerOptions>
): Fn

export function useEventListener(...args: any[]) {
let target: MaybeComputedRef<EventTarget> | undefined
let events: Arrayable<string>
let listeners: Arrayable<Function>
let options: any
let options: MaybeComputedRef<boolean | AddEventListenerOptions> | undefined

if (isString(args[0]) || Array.isArray(args[0])) {
[events, listeners, options] = args
Expand All @@ -133,21 +133,21 @@ export function useEventListener(...args: any[]) {
cleanups.length = 0
}

const register = (el: any, event: string, listener: any) => {
const register = (el: any, event: string, listener: any, options: any) => {
el.addEventListener(event, listener, options)
return () => el.removeEventListener(event, listener, options)
}

const stopWatch = watch(
() => unrefElement(target as unknown as MaybeElementRef),
(el) => {
() => [unrefElement(target as unknown as MaybeElementRef), resolveUnref(options)],
([el, options]) => {
cleanup()
if (!el)
return

cleanups.push(
...(events as string[]).flatMap((event) => {
return (listeners as Function[]).map(listener => register(el, event, listener))
return (listeners as Function[]).map(listener => register(el, event, listener, options))
}),
)
},
Expand Down

0 comments on commit 103d6c0

Please sign in to comment.