kliping.pro
  • Docs
  • Directory
  • Colors
  • Typeset
Hooks
  • State7
  • Advanced6
  • Lifecycle16
  • Browser21
    • useActiveElement
    • useBattery
    • useClickAnyWhere
    • useClickAway
    • useClipboard
    • useDocumentVisibility
    • useElementSize
    • useEventListener
    • useFps
    • useFullscreen
    • useHash
    • useHover
    • useInViewport
    • useIsMatchMedia
    • useIsOnline
    • useMouse
    • useNetwork
    • useOs
    • useScrollLock
    • useTextSelection
    • useTitle
  • Development1
  • Third-Party4
  • Libraries4

useEventListener

PreviousNext

Memasang pendengar peristiwa yang ikut hidup dan mati bersama scope-nya.

Ini fondasi. Sembilan composable lain dibangun di atasnya, jadi kesalahan di sini menyebar ke semuanya — dan kesalahan yang paling mahal bukan salah pasang, melainkan lupa melepas.

Tiga hal yang membedakannya dari addEventListener biasa:

  1. Targetnya boleh reaktif. useTemplateRef() masih null saat setup() berjalan dan baru terisi setelah komponennya terpasang. Karena itu pemasangannya dijalankan lewat watch, bukan sekali di onMounted — target yang berganti di tengah jalan ikut terlayani, pendengar lamanya dilepas lebih dulu.
  2. Dilepas lewat scope, bukan lewat komponen. onScopeDispose bekerja di dalam komponen maupun di dalam effectScope() lepas; onUnmounted hanya yang pertama. Composable ini dipakai composable lain, yang belum tentu dipanggil dari komponen.
  3. Aman di server. Tanpa window, watch-nya tetap jalan dan tidak menemukan apa pun untuk dipasangi. Tidak ada yang meledak.

Handler-nya dipanggil langsung, tanpa penampung apa pun. setup() berjalan sekali, jadi fungsi yang diterima di sini memang sudah yang terbaru selamanya — tidak ada nilai basi yang perlu disegarkan.

Installation ​

pnpm dlx shadcn-vue@latest add @kliping/use-event-listener

Perlu @kliping terdaftar di components.json project Anda. Lihat cara menyiapkannya.

Ikut terpasang sendiri: is-browser, target.

Salin dulu is-browser, target — masing-masing memuat sumbernya di halamannya sendiri — lalu tempel berkas ini.

ts
import { getCurrentScope, onScopeDispose, toValue, watch } from 'vue'
import type { MaybeRefOrGetter } from 'vue'
import { isBrowser } from '@/lib/is-browser'
import { getTargetElement } from '@/lib/target'
import type { BasicTarget } from '@/lib/target'

export interface UseEventListenerOptions {
  /** Element to attach to. Leave empty for `window`. */
  target?: BasicTarget
  capture?: boolean
  once?: boolean
  passive?: boolean
  /** Temporarily disable without removing the call. May be reactive. */
  enable?: MaybeRefOrGetter<boolean>
}

export function useEventListener(
  eventName: string | string[],
  handler: (event: any) => void,
  options: UseEventListenerOptions = {},
) {
  const { capture, once, passive } = options
  const eventNames = Array.isArray(eventName) ? eventName : [eventName]

  let detach: (() => void) | undefined

  const teardown = () => {
    detach?.()
    detach = undefined
  }

  const stopWatch = watch(
    () =>
      [
        options.target === undefined
          ? isBrowser
            ? window
            : undefined
          : getTargetElement(options.target),
        toValue(options.enable ?? true),
      ] as const,

    ([element, enabled]) => {
      teardown()

      if (!enabled || !element?.addEventListener) return

      const listener = (event: Event) => handler(event)

      for (const name of eventNames)
        element.addEventListener(name, listener, { capture, once, passive })

      detach = () => {
        for (const name of eventNames) element.removeEventListener(name, listener, { capture })
      }
    },

    { immediate: true, flush: 'post' },
  )

  const stop = () => {
    teardown()
    stopWatch()
  }

  if (getCurrentScope()) onScopeDispose(stop)

  return stop
}

API ​

ts
export interface UseEventListenerOptions {
  /** Element to attach to. Leave empty for `window`. */
  target?: BasicTarget
  capture?: boolean
  once?: boolean
  passive?: boolean
  /** Temporarily disable without removing the call. May be reactive. */
  enable?: MaybeRefOrGetter<boolean>
}

export function useEventListener(
  eventName: string | string[],
  handler: (event: any) => void,
  options: UseEventListenerOptions = {},
)
PrevioususeElementSizeNext useFps

On This Page

InstallationAPI
Dirilis di bawah lisensi MIT. Ditulis ulang untuk Vue dari shadcn-vue, shadcn-ui-blocks, dan shadcn-hooks. Hak cipta © 2026 Kliping