useIntersectionObserver组件数据懒加载和图片懒加载

822 阅读3分钟
    如果一上来就加载页面中所有的数据,并渲染所有页面中的内容,必然发送很多次无效的请求,所以为了提高性能  我们使用可以懒加载的方式  等所在模块进入到 可视区域 在发送请求获取数据 ,这里我们使用的是`@vueuse/core` 中的`useIntersectionObserver` 来实现监听组件进入可视区域的行为

首先我们试着分析一些useIntersectionObserver 函数

import { useIntersectionObserver } from '@vueuse/core'
const { stop } = useIntersectionObserver(
  target,
  ([{ isIntersecting }], observerElement) => {
    targetIsVisible.value = isIntersecting
  }
)
  • stop 一个可执行的函数用来停止监听行为
  • target 一个由ref api调用之后形成的RefImpl对象 也可以是一个dom对象
  • isIntersecting 一个类型为布尔值的数据 当被监听元素进入视口区域时为true,离开视口区域时为false
  • observerElement 被观察的dom
  • 特别注意: 对于目标target是否进入视口区域的监听会一直进行不会只监听一次

组件数据懒加载

当进入可是区域的时候 在加载可视区域内的数据--画个简图 希望能有助于理解吧 画的不好 见谅。---页面区域既是你可以看到的可视区域

image.png

在公共组件内定义一个数据懒加载的函数

我这里是定义在了文件compositions内,

import { useIntersectionObserver } from '@vueuse/core'
import { ref } from 'vue'
export function useObserver (apiFn) {
  const target = ref(null)
  const { stop } = useIntersectionObserver(
    // target 是观察的目标dom容器,必须是dom容器,而且是vue3.0方式绑定的dom对象
    target,
    // isIntersecting 是否进入可视区域,true是进入 false是移出
    // observerElement 被观察的dom
    ([{ isIntersecting }], observerElement) => {
      // 在此处可根据isIntersecting来判断,然后做业务
      //会打印true 或者false
       console.log(isIntersecting, 888)
      if (isIntersecting) {
        stop()// 关闭监听
        // apiFn && apiFn()
        if (apiFn) {
          apiFn()
        }
      }
    }
  )
  return target
}


引入 通过ref属性获得组件实例并测试

如果不在使用数据懒加载的那个区域 就打印false 到你使用数据懒加载的区域了 会打印true

import { useObserver } from '../../../compositions'

使用

export default {
 name: 'HomeHot',
 components: {
    HomePanel
  },
  setup () {
   const panelhotLlist = ref([])
   //是我用来获取数据的函数--在dom元素操作区域不进行展示
    const paneLists = async () => {
      const res = await reqFindHot()
      panelhotLlist.value = res.result
    }
    const target = useObserver(paneLists)
   // const target = useObserver(数据接口-获取数据的那个函数)
    return {panelnewList, target }
  }
 }

在操作dom的区域 通过ref属性获得组件实例并测试

HomePanel是我们定义的一个组件,这里需要使用你们自己组件

<template>
  <!-- 和模板关联 -->
  <HomePanel ref="target" title="123" subTitle="123123123">
    .....
  </HomePanel>
</template>

这样 一个组件数据懒加载就完成了。。

图片懒加载

图片懒加载 需要封装一个自定义指令 下面一起说了吧

  • 首先看一下vue2 和 vue3 封装自定义指令的区别
// vue2  
Vue.directive(指令名, {
	inserted (el, binding) {
        
	}
})

// vue3
app.directive(指令名, {
    // 指令所在的元素,dom结构被解析完成
    mounted (el, binding) {
        
    }
})

使用 v3 封装自定义指令v-imgLazy

  • 核心思路:监听图片是否进入到可视区域 正式进入可视区域之后将图片url数据交给img标签的src属性
  1. 我是在direcives文件夹中 以插件的方式 全局注册指令插件
//导入一个 默认图片路径 用做默认显示的图片
import defaltImg from '@/assets/images/200.png'
// 引入监听是否进入视口
import { useIntersectionObserver } from '@vueuse/core'
export default {
  // 需要拿到main.js中由createApp方法产出的app实例对象
  install (app) {
    // app实例身上有我们想要的全局注册指令方法  调用即可
    app.directive('imgLazy', {
      mounted (el, binding) {
        // el:img dom对象
        // binding.value  图片url地址
        // 使用vueuse/core提供的监听api 对图片dom进行监听 正式进入视口才加载
        // img.src = url
        console.log(el, binding)
        const { stop } = useIntersectionObserver(
          // 监听目标元素
          el,
          ([{ isIntersecting }], observerElement) => {
            if (isIntersecting) {
              // 当图片url无效加载失败的时候使用默认图片替代
              el.onerror = function () {
                el.src = defaltImg
              }
              el.src = binding.value
              stop()
            }
          })
      }
    })
  }
}
  1. 在mian.js中注册插件
// 全局注册自定义指令
import directivesPlugin from '@/directives'
createApp(App)
.use(directivesPlugin)
.mount('#app')
  1. 在需要使用的地方使用即可 样式如下
<img v-imgLazy="item.picture" alt="" />