Memulai
Siklus Hidup
Peramban
Pengembangan
Paket Luar
useInViewport
Apakah sebuah elemen sedang terlihat di layar.
Terlihat: — · rasio —
Gulung ke bawah…
Kotak yang dipantau.
IntersectionObserver, bukan menghitung posisi saat scroll. Bedanya bukan gaya: menghitung posisi berarti bekerja di setiap peristiwa scroll, di utas utama, untuk setiap elemen yang dipantau. IntersectionObserver dikerjakan peramban di luar itu dan cuma memanggil balik saat keadaannya benar-benar berubah.
Ini yang dipakai untuk memuat gambar saat mendekat, menandai bagian aktif di daftar isi, dan memuat halaman berikutnya saat dasar daftar tersentuh.
Pemasangan
npx shadcn-vue@latest add @kliping/use-in-viewport Perlu @kliping terdaftar di components.json project Anda. Lihat cara menyiapkannya.
Ikut terpasang sendiri: target.
Salin dulu target — masing-masing memuat sumbernya di halamannya sendiri — lalu tempel berkas ini.
ts
import { getCurrentScope, onScopeDispose, ref, watch } from 'vue'
import { bacaElemen } from '@/lib/target'
import type { TargetElemen } from '@/lib/target'
export interface UseInViewportOptions {
rootMargin?: string
threshold?: number | number[]
/** Elemen yang dianggap "layar". Kosongkan untuk viewport. */
root?: TargetElemen
callback?: (entri: IntersectionObserverEntry) => void
}
export function useInViewport(
target: TargetElemen | TargetElemen[],
options: UseInViewportOptions = {},
) {
const { rootMargin, threshold, root, callback } = options
const inViewport = ref<boolean | undefined>(undefined)
const ratio = ref<number | undefined>(undefined)
let pengamat: IntersectionObserver | undefined
const bongkar = () => {
pengamat?.disconnect()
pengamat = undefined
}
const berhentiPantau = watch(
() => {
const daftar = Array.isArray(target) ? target : [target]
return daftar.map(t => bacaElemen(t))
},
(elemen) => {
bongkar()
const ada = elemen.filter(Boolean) as Element[]
if (!ada.length || typeof IntersectionObserver === 'undefined')
return
pengamat = new IntersectionObserver(
(daftar) => {
for (const entri of daftar) {
ratio.value = entri.intersectionRatio
inViewport.value = entri.isIntersecting
callback?.(entri)
}
},
{
rootMargin,
threshold,
root: bacaElemen(root) as Element | null ?? null,
},
)
for (const el of ada)
pengamat.observe(el)
},
{ immediate: true, flush: 'post' },
)
const berhenti = () => {
bongkar()
berhentiPantau()
}
if (getCurrentScope())
onScopeDispose(berhenti)
return { inViewport, ratio, stop: berhenti }
}API
ts
export interface UseInViewportOptions {
rootMargin?: string
threshold?: number | number[]
/** Elemen yang dianggap "layar". Kosongkan untuk viewport. */
root?: TargetElemen
callback?: (entri: IntersectionObserverEntry) => void
}
export function useInViewport(
target: TargetElemen | TargetElemen[],
options: UseInViewportOptions = {},
)