Lazy loading of component data - basic use
Goal: Optimize fresh goodies and popular recommendation modules through useIntersectionObserver
E-commerce websites, especially the homepage, have several screens of content. If you load the data of all screens and render the content of all screens, the homepage will load very slowly.
Data lazy loading: When the component officially enters the visible area, the ajax request inside the component is initiated, otherwise no data is requested
(1) Optimize fresh products
<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) Optimize popularity recommendation
<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>
Add component type to ref
Reference link: 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>
Component data lazy loading - encapsulation
Goal: Encapsulate component data lazy loading and reusable logic
analyze
On the home page, component data lazy loading should be used in many places. No matter which module is used, the following code will be written repeatedly
In fact, the only thing that may change with business usage is the call of the ajax interface
We reuse the rest and extract it into reusable logic
Core code:
(1) Encapsulate the general lazy loading data apisrc/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) Optimize fresh products
<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) Optimize popularity recommendation
<script lang="ts" setup>
const target = useLazyData(() => {
home.getHotList()
})
</script>
<template>
<HomePanel ref="target" title="人气推荐" sub-title="人气爆款 不容错过">
</HomePanel>
</template>
Expand small knowledge: custom lazyhook type optimization
export function useLazyApi(apiFn: () => void) {
const target = ref<MaybeElementRef | null>(null)
const {
stop} = useIntersectionObserver(target, ([{
isIntersecting}]) => {
if (isIntersecting) {
stop()
apiFn()
}
})
return target
}
Added ref type hint: MaybeElementRef -> exposed taget will prompt if the assignment type is wrong
Take a look at what type MaybeElementRef is?
declare type MaybeElementRef<T extends MaybeElement = MaybeElement> = MaybeRef<T>;
declare type MaybeElement = HTMLElement | SVGElement | VueInstance | undefined | null;
declare type MaybeRef<T> = T | Ref<T>;
To summarize: The types of the MaybeElementRef type are:
- Ref type of MaybeElement
- Or directly for the MayBeElement type
Home page main body - scroll loading product bug
- The product area needs to scroll more to load the data.
- threshold The ratio of the intersection of the container and the visible area (entered area/complete area of the container) Value, between 0-1, the default is greater than 0, so more scrolling is required to trigger the event of entering the visible area. Threshold (area entered/full area of container)
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
}
)