简单封装一个数据懒加载组件 ( Vue3 )

698 阅读2分钟

应用场景

在电商网站中,当某个商品模块进入可视区域后才去请求加载数据,如果没有进入可视区域,不发ajax请求

实现

我们该如何判断dom元素是否进入可见区域?

1.传统:获取dom的位置然后手动判断
2.直接判断元素进入可视区域的比例

Intersection Observer接口提供了一种异步观察目标元素与其祖先元素或顶级文档视窗交叉状态的方法
当一个IntersectionObserver对象被创建时,其被配置为监听根中一段给定比例的可见区域

实例

使用@vueuse/core中的useintersectionObserver函数来实现

定义

// stop是一个函数,调用的话就会停止 (是否进入或移出可视区域的行为)
// target是观察的目标容器 dom对象|组件对象
// isInterseting是一个布尔值,表示是否进入可视区域,true表示进入,false表示移出
const { stop } = useintersectionObserver (
  target,
  ( [{ isInterseting }] , observerElement ) => {
    // 根据判断进行业务
  }
)

封装

import { ref } from 'vue'
import { useIntersectionObserver } from '@vueuse/core'

/**
 * 功能:数据懒加载
 * @param {*} fn 当目标可见时,要调用一次的函数
 * @returns target 要观察的目标
 */
const useLazyData = (fn) => {
  const target = ref(null)
  const { stop } = useIntersectionObserver(
    target,
    ([{ isIntersecting }], observerElement) => {
      if (isIntersecting) {
        stop()
        // console.log(target, stop, 'homehot')
        // findHot().then(data => {
        //   hotList.value = data.result
        // })
        fn()
      }
    }
  )
  return target
}

export default useLazyData

使用

image.png

image.png

注意 为什么要stop()?

image.png

image.png

效果

image.png

image.png

如果遇到懒加载的元素比较大的话?

image.png

因为useIntersectionObserver默认以进入视口的面积占总元素面积的0.1为基准判断是否进入

image.png

解决方法,补充一个参数

const { stop } = useIntersectionObserver(
    target,
    ([{ isIntersecting }], observerElement) => {
      if (isIntersecting) {
        stop()
        fn()
      }
+   },{
+     threshold: 0
      // threshold容器和可视区交叉的占比(进入的面积/容器完整面积),取值0-1.默认0.1,所以需要滚动较多才能触发进入可视区域事件
+   }
  )

更改后效果

image.png