@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
为请求的数据,可进行渲染页面,target
为ref
值