组件数据懒加载-基本使用
目标:通过useIntersectionObserver优化新鲜好物和人气推荐模块
电商类网站,尤其是首页,内容有好几屏,而如果一上来就加载所有屏的数据,并渲染所有屏的内容会导致首页加载很慢。
数据懒加载:等组件正式进入到可视区中时,才把组件内部的ajax请求发起,否则不请求数据
(1)优化新鲜好物
<script lang="ts" setup>
const { home } = useStore()
const target = ref(null)
const { stop } = useIntersectionObserver(target, ([{ isIntersecting }]) => {
console.log(isIntersecting)
// isIntersecting 是否进入可视区域,true是进入 false是移出
if (isIntersecting) {
home.getNewList()
stop()
}
})
</script>
<template>
<div class="home-new">
<HomePanel ref="target" title="新鲜好物" sub-title="新鲜出炉 品质靠谱">
</HomePanel>
</div>
</template>
(2)优化人气推荐
<script lang="ts" setup>
const { home } = useStore()
const target = ref(null)
const { stop } = useIntersectionObserver(target, ([{ isIntersecting }]) => {
console.log(isIntersecting)
// isIntersecting 是否进入可视区域,true是进入 false是移出
if (isIntersecting) {
home.getHotList()
stop()
}
})
</script>
<template>
<HomePanel ref="target" title="人气推荐" sub-title="人气爆款 不容错过">
</HomePanel>
</template>
给ref添加组件类型
参考链接:https://staging-cn.vuejs.org/guide/typescript/composition-api.html#typing-component-template-refs
<!-- App.vue -->
<script setup lang="ts">
import MyModal from './MyModal.vue'
const modal = ref<InstanceType<typeof MyModal> | null>(null)
const openModal = () => {
modal.value?.open()
}
</script>
组件数据懒加载-封装
目标:封装组件数据懒加载可复用的逻辑
分析
首页中,很多地方都应该使用组件数据懒加载这个功能,不管是哪个模块使用,下面代码都会重复书写
事实上,唯一可能会随着业务使用发生变化的是 ajax接口的调用
其余的部分我们进行重复使用,抽离为可复用逻辑
核心代码:
(1)封装通用的懒加载数据api src/utils/hooks.ts
// 自定义一些通用的compositions api
import { useIntersectionObserver } from '@vueuse/core'
import { ref } from 'vue'
// 封装通用的数据懒加载api
export function useLazyData(apiFn: () => void) {
// 通过 ref 获得组件实例
const target = ref(null)
const { stop } = useIntersectionObserver(
// target 是观察的目标dom容器,必须是dom容器,而且是vue3.0方式绑定的dom对象
target,
// isIntersecting 是否进入可视区域,true是进入 false是移出
// observerElement 被观察的dom
([{ isIntersecting }]) => {
// 在此处可根据isIntersecting来判断,然后做业务
if (isIntersecting) {
stop()
apiFn()
}
}
)
return target
}
(2)优化新鲜好物
<script lang="ts" setup>
const target = useLazyData(() => {
home.getNewList()
})
</script>
<template>
<div class="home-new">
<HomePanel ref="target" title="新鲜好物" sub-title="新鲜出炉 品质靠谱">
</HomePanel>
</div>
</template>
(3)优化人气推荐
<script lang="ts" setup>
const target = useLazyData(() => {
home.getHotList()
})
</script>
<template>
<HomePanel ref="target" title="人气推荐" sub-title="人气爆款 不容错过">
</HomePanel>
</template>
拓展小知识:自定义lazyhook的类型优化
export function useLazyApi(apiFn: () => void) {
const target = ref<MaybeElementRef | null>(null)
const {stop} = useIntersectionObserver(target, ([{isIntersecting}]) => {
if (isIntersecting) {
stop()
apiFn()
}
})
return target
}
添加了ref类型提示:MaybeElementRef -> 暴露出去的taget如果赋值类型不对会进行提示
看一下MaybeElementRef到底是什么类型?
declare type MaybeElementRef<T extends MaybeElement = MaybeElement> = MaybeRef<T>;
declare type MaybeElement = HTMLElement | SVGElement | VueInstance | undefined | null;
declare type MaybeRef<T> = T | Ref<T>;
总结:MaybeElementRef类型的类型为:
- MaybeElement的Ref类型
- 或者直接为MayBeElement类型
首页主体-滚动加载商品的bug
- 产品区域需要滚动比较多才能去加载数据。
- threshold 容器和可视区交叉的占比(进入的面积/容器完整面积) 取值,0-1 之间,默认比0大,所以需要滚动较多才能触发进入可视区域事件。 阈值 (进入的面积/容器完整面积)
const { stop } = useIntersectionObserver(
target,
([{ isIntersecting }], observerElement) => {
if (isIntersecting) {
stop()
// 调用API获取数据
apiFn().then(data => {
result.value = data.result
})
}
},
{
threshold: 0
}
)
rElement) => {
if (isIntersecting) {
stop()
// 调用API获取数据
apiFn().then(data => {
result.value = data.result
})
}
},
{
threshold: 0
}
)