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

useInViewport

PreviousNext

Apakah sebuah elemen sedang terlihat di layar.

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.

Installation ​

pnpm dlx 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 { getTargetElement } from '@/lib/target'
import type { BasicTarget } from '@/lib/target'

export interface UseInViewportOptions {
  rootMargin?: string
  threshold?: number | number[]
  /** Element treated as the "screen". Leave empty for the viewport. */
  root?: BasicTarget
  callback?: (entry: IntersectionObserverEntry) => void
}

export function useInViewport(
  target: BasicTarget | BasicTarget[],
  options: UseInViewportOptions = {},
) {
  const { rootMargin, threshold, root, callback } = options

  const inViewport = ref<boolean | undefined>(undefined)
  const ratio = ref<number | undefined>(undefined)

  let observer: IntersectionObserver | undefined

  const teardown = () => {
    observer?.disconnect()
    observer = undefined
  }

  const stopWatch = watch(
    () => {
      const targets = Array.isArray(target) ? target : [target]
      return targets.map((t) => getTargetElement(t))
    },
    (elements) => {
      teardown()

      const present = elements.filter(Boolean) as Element[]
      if (!present.length || typeof IntersectionObserver === 'undefined') return

      observer = new IntersectionObserver(
        (entries) => {
          for (const entry of entries) {
            ratio.value = entry.intersectionRatio
            inViewport.value = entry.isIntersecting
            callback?.(entry)
          }
        },
        {
          rootMargin,
          threshold,
          root: (getTargetElement(root) as Element | null) ?? null,
        },
      )

      for (const el of present) observer.observe(el)
    },
    { immediate: true, flush: 'post' },
  )

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

  if (getCurrentScope()) onScopeDispose(stop)

  return { inViewport, ratio, stop: stop }
}

API ​

ts
export interface UseInViewportOptions {
  rootMargin?: string
  threshold?: number | number[]
  /** Element treated as the "screen". Leave empty for the viewport. */
  root?: BasicTarget
  callback?: (entry: IntersectionObserverEntry) => void
}

export function useInViewport(
  target: BasicTarget | BasicTarget[],
  options: UseInViewportOptions = {},
)
PrevioususeHoverNext useIsMatchMedia

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