Memulai
Siklus Hidup
Peramban
Pengembangan
Paket Luar
useElementSize
Ukuran sebuah elemen, diikuti lewat ResizeObserver.
0 × 0 px
Ukuran sebuah elemen, diikuti lewat ResizeObserver.
Dua hal yang dibawa dari sumbernya karena keduanya jawaban atas masalah nyata, bukan kerumitan yang bisa dibuang:
- SVG diukur lewat
getBoundingClientRect.contentBoxSizeuntuk elemen SVG dilaporkan berbeda-beda antar peramban, dan sebagiannya nol. observedengan opsiboxdibungkus try/catch. Peramban lama melempar untuk nilaiboxyang tidak dikenalnya; pengamatan tanpa opsi tetap lebih baik daripada tidak mengamati sama sekali.
Pemasangan
npx shadcn-vue@latest add @kliping/use-element-size 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 UkuranElemen {
width: number
height: number
}
export interface UseElementSizeOptions {
/** Kotak yang diukur. Bawaan: `content-box`. */
box?: ResizeObserverBoxOptions
}
function ukuranDariEntri(
entri: ResizeObserverEntry,
box: ResizeObserverBoxOptions,
): UkuranElemen {
const kotak = box === 'border-box'
? entri.borderBoxSize
: box === 'device-pixel-content-box'
? entri.devicePixelContentBoxSize
: entri.contentBoxSize
const daftar = kotak
? (Array.isArray(kotak) ? kotak : [kotak]) as readonly ResizeObserverSize[]
: []
if (daftar.length) {
return {
width: daftar.reduce((n, u) => n + u.inlineSize, 0),
height: daftar.reduce((n, u) => n + u.blockSize, 0),
}
}
return { width: entri.contentRect.width, height: entri.contentRect.height }
}
export function useElementSize(
target: TargetElemen,
initialSize: UkuranElemen = { width: 0, height: 0 },
options: UseElementSizeOptions = {},
) {
const { box = 'content-box' } = options
const width = ref(initialSize.width)
const height = ref(initialSize.height)
let pengamat: ResizeObserver | undefined
const bongkar = () => {
pengamat?.disconnect()
pengamat = undefined
}
const setel = (ukuran: UkuranElemen) => {
width.value = ukuran.width
height.value = ukuran.height
}
const berhentiPantau = watch(
() => bacaElemen(target),
(elemen) => {
bongkar()
if (!elemen || !('getBoundingClientRect' in elemen)) {
setel({ width: 0, height: 0 })
return
}
const el = elemen as Element
if (typeof ResizeObserver === 'undefined') {
const kotak = el.getBoundingClientRect()
setel({ width: kotak.width, height: kotak.height })
return
}
const svg = typeof SVGElement !== 'undefined' && el instanceof SVGElement
pengamat = new ResizeObserver((daftar) => {
const entri = daftar[0]
if (!entri)
return
if (svg) {
const kotak = el.getBoundingClientRect()
setel({ width: kotak.width, height: kotak.height })
return
}
setel(ukuranDariEntri(entri, box))
})
try {
pengamat.observe(el, { box })
}
catch {
pengamat.observe(el)
}
},
{ immediate: true, flush: 'post' },
)
const berhenti = () => {
bongkar()
berhentiPantau()
}
if (getCurrentScope())
onScopeDispose(berhenti)
return { width, height, stop: berhenti }
}API
ts
export interface UkuranElemen {
width: number
height: number
}
export interface UseElementSizeOptions {
/** Kotak yang diukur. Bawaan: `content-box`. */
box?: ResizeObserverBoxOptions
}
export function useElementSize(
target: TargetElemen,
initialSize: UkuranElemen = { width: 0, height: 0 },
options: UseElementSizeOptions = {},
)