实现vueuse中useElementVisibility的自定义hook
在vueuse我看到一个很好用的方法useElementVisibility,它可以帮助我们判断元素是否在屏幕的可视区域内,可以用来懒加载图片列表或一些其他功能。实现它的核心代码就几行,在实现之前需要了解一些属性。
Element.getBoundingClientRect()
domRect = element.getBoundingClientRect();
它的返回值是一个DOMRect对象,这个对象是一组矩形的集合,就是该元素的 CSS 边框大小。返回的结果是包含完整元素的最小矩形,并且拥有left, top, right, bottom, x, y, width, 和 height这几个以像素为单位的只读属性用于描述整个边框。除了width 和 height 以外的属性是相对于视图窗口的左上角来计算的。

知道这些后就可以来实现效果了。
函数需要接收一个ref的节点,作为判断位置的参数
创建一个ref<boolean>值用来记录元素是否显示
const elementIsVisibility = ref(false)
创建一个函数来判断元素位置
const testBounding = () => { // 判断传入是否有值 if (!element.value) { elementIsVisibility.value = false } else { const rect = element.value.getBoundingClientRect() elementIsVisibility.value = ( rect.top <= (window.innerHeight || document.documentElement.clientHeight) && rect.left <= (window.innerWidth || document.documentElement.clientWidth) && rect.bottom >= 0 && rect.right >= 0 ) } }
这里也可以用
- top 大于等于 0
- left 大于等于 0
- bottom 小于等于视窗高度
- right 小于等于视窗宽度
function isInViewPort(element) { const viewWidth = window.innerWidth || document.documentElement.clientWidth; const viewHeight = window.innerHeight || document.documentElement.clientHeight; const { top, right, bottom, left, } = element.getBoundingClientRect(); return ( top >= 0 && left >= 0 && right <= viewWidth && bottom <= viewHeight ); }
判断后在Vue生命周期中给window添加scroll监听
onMounted(() => { useEventListener('scroll', testBounding, { capture: false, passive: true }) })
这里passive: true可以改善滚屏性能,具体可以在MDN上查看。
最后将变量返回
import { ref, onMounted } from "vue";
import { useEventListener } from "./useEventListener";
export function useElementVisibility(
element//传入需要判断的节点的ref
) {
// const window = Window
const document = window.document
const elementIsVisibility = ref(false)
const testBounding = () => {
// 判断传入是否有值
if (!element.value) {
elementIsVisibility.value = false
} else {
const rect = element.value.getBoundingClientRect()
elementIsVisibility.value = (
rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.left <= (window.innerWidth || document.documentElement.clientWidth) &&
rect.bottom >= 0 &&
rect.right >= 0
)
}
}
onMounted(() => {
useEventListener('scroll', testBounding, { capture: false, passive: true })
})
return elementIsVisibility
}

浙公网安备 33010602011771号