Memulai
Siklus Hidup
Peramban
Pengembangan
Paket Luar
useActiveElement
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 = {})