vue3.0项目- 利用@vueuse/core实现组件数据懒加载

2,420 阅读1分钟

@vueuse/core实现组件数据懒加载

  • 目的: 实现当组件进入可视区域再加载数据。
  • 核心: 利用 @vueuse/core 中的 useIntersectionObserver 来监听组件进入视图区域的行为
  • 注意:必须配合vue3.0的组合API的方式才能实现。

useIntersectionObserver 函数介绍

const { stop } = useIntersectionObserver(target, fn, options)
  • target: 表示被监听的DOM元素,必须是dom容器,而且是vue3.0方式绑定的dom对象
  • fn: 回调函数,用于通知监听的动作(回调函数的第一个形参 isIntersecting 表示被监听的元素已经进入了可视区)
  • options: 配置选项

基本用法

// stop 是停止观察是否进入或移出可视区域的行为    
const { stop } = useIntersectionObserver(target,([{ isIntersecting }], observerElement) => {
    // 在此处可根据isIntersecting来判断,然后做业务
  },
  // isIntersecting 是否进入可视区域,true是进入 false是移出
  // observerElement 被观察的dom
)

实现组件数据懒加载

// MyComponent.vue

<template>
  <div ref="target">
      <div>
          <ul>
            <li v-for="item in goods" :key="item.id">
              <RouterLink :to="`/${item.id}`">
                <img :src="item.picture" alt="" />
                <p>{{ item.name }}</p>
                <p>{{ item.price }}</p>
              </RouterLink>
            </li>
          </ul>
      </div>
  </div>
</template>

<script>
import { ref } from 'vue'
// 引入 @vueuse/core
import { useIntersectionObserver } from '@vueuse/core'
import { findNewAPI } from '@/api'

export default {
  name: 'MyComponent',
  setup() {
    const goods = ref([])
    const target = ref[null]
    const { stop } = useIntersectionObserver(target, ([{ isIntersecting }]) => {
      if(isIntersecting) {
        // isIntersecting 为 true,证明 target 进入可视区, 此时发起请求
        findNewAPI().then(ret => goods.value = ret.data)
        // 取消监听组件进入视图区域这一行为
        stop()
      }
    })
    return { goods, target }
  }
}
</script>

此时已经实现组件 MyComponent 中的数据懒加载, 但在项目中,为了便于多处使用,可将该方法进行封装,通常在 src/hooks/index.js 中

// src/hooks/index.js
import { ref } from 'vue'
import { useIntersectionObserver } from '@vueuse/core'

export const useLazyData = (apiFn) => {
  const goods = ref([])
  const target = ref[null]
  const { stop } = useIntersectionObserver(target, ([{ isIntersecting }]) => {
    if(isIntersecting) {
      // isIntersecting 为 true,证明 target 进入可视区, 此时发起请求
      apiFn().then(ret => goods.value = ret.data)
      // 取消监听组件进入视图区域这一行为
        stop()
     }
   })
  return { goods, target }
}

组件中

// MyComponent.vue

<template>
  <div ref="target">
      <div>
          <ul>
            <li v-for="item in goods" :key="item.id">
              <RouterLink :to="`/${item.id}`">
                <img :src="item.picture" alt="" />
                <p>{{ item.name }}</p>
                <p>{{ item.price }}</p>
              </RouterLink>
            </li>
          </ul>
      </div>
  </div>
</template>

<script>
import { findNewAPI } from '@/api'
import { useLazyData } from '@/hooks'
export default {
  name: 'MyComponent',
  setup() {
    const { goods, target } = useLazyData(findNewAPI)
    return { goods, target }
  }
}
</script>

之后使用步骤

  • 在最外层 dom 元素上增加 ref 属性, 且值为 target
  • 引入 hooks 中封装的 useLazyData 方法
  • 将封装好的 api 函数传给 useLazyData 方法, 并接收 goods, target
  • 此时: goods 为请求的数据,可进行渲染页面, targetref