2.4 Elements – useElementBounding
https://vueuse.org/core/useElementBounding/
作用
把一个html
元素变成响应式盒子
官方示例
<template>
<div ref="el" />
</template>
<script>
import { ref } from 'vue'
import { useElementBounding } from '@vueuse/core'
export default {
setup() {
const el = ref(null)
const { x, y, top, right, bottom, left, width, height } = useElementBounding(el)
return {
el,
/* ... */
}
}
}
</script>
无渲染组件用法如下:
<UseElementBounding v-slot="{ width, height }">
Width: {{ width }}
Height: {{ height }}
</UseElementBounding>
源码分析
核心是使用getBoundingClientRect
获取target
的信息。主要看哪些场景会触发update
。
官方示例中的元素可变大小,是通过css
属性实现的: resize: both;
export function useElementBounding(
target: MaybeComputedElementRef,
options: UseElementBoundingOptions = {},
) {
const {
reset = true,
windowResize = true,
windowScroll = true,
immediate = true,
} = options
const height = ref(0)
const bottom = ref(0)
const left = ref(0)
const right = ref(0)
const top = ref(0)
const width = ref(0)
const x = ref(0)
const y = ref(0)
function update() {
const el = unrefElement(target)
if (!el) {
if (reset) {
height.value = 0
bottom.value = 0
left.value = 0
right.value = 0
top.value = 0
width.value = 0
x.value = 0
y.value = 0
}
return
}
/**
* 核心API
*/
const rect = el.getBoundingClientRect()
height.value = rect.height
bottom.value = rect.bottom
left.value = rect.left
right.value = rect.right
top.value = rect.top
width.value = rect.width
x.value = rect.x
y.value = rect.y
}
// target大小变化,触发update
useResizeObserver(target, update)
// target被销毁了,触发update
watch(() => unrefElement(target), ele => !ele && update())
// 页面滚动,触发update
// passive: true,显式告诉浏览器,回调中不会阻止默认事件。这有利于减少浏览器等待时间,提高性能。
if (windowScroll)
useEventListener('scroll', update, { capture: true, passive: true })
/// 页面大小变化,触发update
if (windowResize)
useEventListener('resize', update, { passive: true })
tryOnMounted(() => {
// 如果immediate,在onMounted之后,触发update
if (immediate)
update()
})
return {
height,
bottom,
left,
right,
top,
width,
x,
y,
update,
}
}