Vue3中的组件数据懒加载
作者:itpeilibo
这篇文章主要介绍了Vue3中的组件数据懒加载问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
组件数据懒加载-基本使用
目标:通过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 } )
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。