Kliping
KlipingBerandaDokumentasiKomponenBlocksVariasiTemplateDice UIHooks
Memulai
  • Pengenalan
  • Instalasi
  • Kredit
State
  • useBoolean
  • useControllableValue
  • useCounter
  • useDebounce
  • useResetState
  • useThrottle
  • useToggle
Lanjutan
  • useCreation
  • useCustomCompareEffect
  • useLatest
  • useLockFn
  • useMemoizedFn
  • usePrevious
Siklus Hidup
  • useDebounceEffect
  • useDebounceFn
  • useDeepCompareEffect
  • useDeepCompareLayoutEffect
  • useEffectEvent
  • useEffectWithTarget
  • useInterval
  • useIsHydrated
  • useIsomorphicLayoutEffect
  • useMount
  • useThrottleEffect
  • useThrottleFn
  • useTimeout
  • useUnmount
  • useUpdate
  • useUpdateEffect
Peramban
  • useActiveElement
  • useBattery
  • useClickAnyWhere
  • useClickAway
  • useClipboard
  • useDocumentVisibility
  • useElementSize
  • useEventListener
  • useFps
  • useFullscreen
  • useHash
  • useHover
  • useInViewport
  • useIsMatchMedia
  • useIsOnline
  • useMouse
  • useNetwork
  • useOs
  • useScrollLock
  • useTextSelection
  • useTitle
Pengembangan
  • useWhyDidYouUpdate
Paket Luar
  • useMcp
  • useQuery
  • useStickToBottom
  • useSwr
Pustaka
  • isBrowser
  • createContext
  • bacaElemen
  • saatTerpasang

useActiveElement

SebelumnyaBerikutnya

Elemen yang sedang menerima fokus.

Sedang fokus: —

Dipantau lewat focus dan blur pada fase capture. Itu bukan detail gaya: keduanya tidak menggelembung, jadi pendengar biasa di window tidak akan pernah mendengarnya sama sekali.

blur diabaikan kalau relatedTarget terisi — artinya fokusnya cuma pindah ke elemen lain, dan focus berikutnya sudah akan melaporkannya. Yang ditangani di sini adalah fokus yang benar-benar keluar dari halaman.

Pemasangan ​

npx shadcn-vue@latest add @kliping/use-active-element

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

Ikut terpasang sendiri: is-browser, saat-terpasang, use-event-listener.

Salin dulu is-browser, saat-terpasang, target, use-event-listener — masing-masing memuat sumbernya di halamannya sendiri — lalu tempel berkas ini.

ts
import { getCurrentScope, onScopeDispose, readonly, shallowRef } from 'vue'
import { isBrowser } from '@/lib/is-browser'
import { saatTerpasang } from '@/lib/saat-terpasang'
import { useEventListener } from '@/composables/use-event-listener'

export interface UseActiveElementOptions {
  /** Telusuri sampai ke dalam shadow root yang terbuka. Bawaan: true. */
  deep?: boolean
  /** Periksa ulang saat simpul DOM dihapus. Bawaan: false. */
  triggerOnRemoval?: boolean
}

function cariElemenAktif(deep: boolean): Element | null {
  if (!isBrowser)
    return null

  let aktif: Element | null = document.activeElement
  if (!deep)
    return aktif

  while (aktif?.shadowRoot?.activeElement)
    aktif = aktif.shadowRoot.activeElement

  return aktif
}

export function useActiveElement(options: UseActiveElementOptions = {}) {
  const { deep = true, triggerOnRemoval = false } = options

  // Sengaja tidak dibaca saat setup: di server tidak ada `document`, dan di
  // peramban gambaran pertama harus sama dengan yang dari server.
  const aktif = shallowRef<Element | null>(null)

  const perbarui = () => {
    aktif.value = cariElemenAktif(deep)
  }

  useEventListener('focus', perbarui, { capture: true })
  useEventListener('blur', (event: FocusEvent) => {
    if (event.relatedTarget !== null)
      return
    perbarui()
  }, { capture: true })

  let pengamat: MutationObserver | undefined

  saatTerpasang(() => {
    perbarui()

    if (!triggerOnRemoval || typeof MutationObserver === 'undefined')
      return

    pengamat = new MutationObserver(perbarui)
    pengamat.observe(document, { childList: true, subtree: true })
  })

  // Pengamatnya bukan pendengar peristiwa, jadi tidak ikut terlepas oleh
  // `useEventListener` di atas. Pelepasannya disebut sendiri, di scope — bukan
  // di `onUnmounted`, supaya tetap bekerja saat dipanggil dari `effectScope`.
  if (getCurrentScope())
    onScopeDispose(() => pengamat?.disconnect())

  return readonly(aktif)
}

API ​

ts
export interface UseActiveElementOptions {
  /** Telusuri sampai ke dalam shadow root yang terbuka. Bawaan: true. */
  deep?: boolean
  /** Periksa ulang saat simpul DOM dihapus. Bawaan: false. */
  triggerOnRemoval?: boolean
}

export function useActiveElement(options: UseActiveElementOptions = {})
useUpdateEffectuseBattery

Di halaman ini

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