组件数据懒加载(vue3)

1、何为组件数据懒加载?

前言

电商项目核心优化技术手段:组件数据懒加载 (首屏渲染优化)

电商类网站,首页内容有好几屏,如果一上来就加载所有屏的数据,并渲染所有屏的内容,必然发送很多次无效的请求,我们应该等所在模块进入到 可视区 再发请求获取数据。

思考

  • 我们一般的数据请求在哪里发起? setup (created)
  • 生命周期钩子函数的特点是什么? 一加载组件,就立刻执行

结论

我们希望组件正式进入到 可视区 中时,才把组件内部的 ajax 请求发起,否则不请求数据,那如何判断进入可视区,并进行组件数据懒加载呢?

2、如何判断组件进入可视区?

技术方案

我们可以使用 @vueuse/core 中的 useIntersectionObserver来实现监听组件进入可视区域行为,
需要配合 vue3.0 的组合 API的方式才能实现

分析useIntersectionObserver 函数:

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

3、实现组件数据懒加载(代码落地)

  1. 通过 ref 属性获得组件实例并测试
  2. 使用 useIntersectionObserver 监听函数
  3. 发送的ajax请求在 isIntersectingtrue 时触发
  4. 一旦触发一次之后停止监听 stop(),防止接口重复调用
<template>
  <HomePanel ref="target" title="人气推荐" sub-title="人气爆款 不容错过">
    <ul  class="goods-list">
      <li v-for="item in hotList" :key="item.id">
        <RouterLink to="/">
          <img :src="item.picture" alt=""> 
          <p class="name">{{item.title}}</p>
          <p class="desc">{{item.alt}}</p>
        </RouterLink>
      </li>
    </ul>
  </HomePanel>
</template>

<script>
// 导入子组件 HomePanel 
import HomePanel from './home-panel'
// 导入获取数据的件接口函数
import { reqFindHot } from '@/api/home'
// 导入 ref 函数(使目标数据变成响应式数据)
import { ref } from 'vue'
// 导入 useIntersectionObserver 进行监听
import { useIntersectionObserver } from '@vueuse/core'
export default {
  name: 'HomeHot',
  components: { HomePanel },// 注册子组件
  setup () {
    const hotList = ref([])
    const getHotList = async () => {
      const res = await reqFindHot()
      hotList.value = res.result
    }
    // getHotList()

    // 1.通过 ref 获得组件实例
    const target = ref(null)
    // 2.使用 useIntersectionObserver 监听函数
    const { stop } = useIntersectionObserver(
      target,// 3.target 是被观察的目标dom容器
      ([{ isIntersecting }], observerElement) => {
        // 4.在此处可根据 isIntersecting 来判断,然后做处理
        console.log(isIntersecting)
        // 5.如果 isIntersecting 为 true 
        if (isIntersecting) {
          stop()// 6.中止监听
          getHotList()// 7.调用函数(发送请求)
        }
      }
    )
    // 8.把 target 返回
    return { hotList, target}
  }
}
</script>
复制代码

4、组件数据懒加载的逻辑复用

事实上,首页中有很多地方都应该使用 组件数据懒加载 这个功能,不管是哪个模块使用,下面代码都会重复书写,可能会随着业务使用发生变化的是 ajax 接口的调用,其余的部分我们进行重复使用,抽离为可复用逻辑。

下面,我们将以上代码抽离出来进行复用:

新建 src/compositions/index.js

// ◆封装组件懒加载的函数
import { ref } from 'vue'
import { useIntersectionObserver } from '@vueuse/core'
// 按需导出
export function useObserver (apiFn) {// apiFn 为形参
  const target = ref(null)
  const { stop } = useIntersectionObserver(
    target,
    ([{ isIntersecting }], observerElement) => {
      console.log(isIntersecting, '666')
      if (isIntersecting) {
        stop()// 终止监听
        apiFn && apiFn()
      }
    }
  )
  return target// 一定要 return 出去
}
复制代码

在需要的页面调用

<template>
  <HomePanel ref="target" title="人气推荐" sub-title="人气爆款 不容错过">
    <ul  class="goods-list">
      <li v-for="item in hotList" :key="item.id">
        <RouterLink to="/">
          <img :src="item.picture" alt=""> 
          <p class="name">{{item.title}}</p>
          <p class="desc">{{item.alt}}</p>
        </RouterLink>
      </li>
    </ul>
  </HomePanel>
</template>

<script>
import HomePanel from './home-panel'
import { reqFindHot } from '@/api/home'
import { ref } from 'vue'
// import { useIntersectionObserver } from '@vueuse/core'
// 1.按需导入封装好的组件懒加载函数
import { useObserver } from '@/compositions'
export default {
  name: 'HomeHot',
  components: { HomePanel },
  setup () {
    const hotList = ref([])
    const getHotList = async () => {
      const res = await reqFindHot()
      hotList.value = res.result
    }
    // 2.调用封装好的函数,传实参过去
    const target = useObserver(getHotList)
    // getHotList()
    return { hotList, target }
  }
}
</script>
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享