Vue项目按需请求,组件数据懒加载—@vueuse/core
中 useIntersectionObserver
的使用
一、通过监听 scroll 事件实现
import { ref } from 'vue';
// 响应式数据,用于是否显示固定头部
const isShow = ref(false);
// 监听浏览器滚动事件
window.addEventListener('scroll', () => {
// 获取滚动出去的距离
const top = document.documentElement.scrollTop;
if (top >= 78) {
// 大于等于 78 显示盒子
isShow.value = true;
} else {
// 反之隐藏盒子
isShow.value = false;
}
});
// tempalte
<div class="app-header-sticky" :class="{ show: isShow }"></div>
二、通过 @vueuse/core
实现
即当模块进入到 可视区 ,再发请求获取数据
使用 @vueuse/core
中的 useIntersectionObserver
来实现监听组件进入可视区域行为,
需要配合 vue3
的组合 API
的方式才能实现 可参考官网
先分析下这个useIntersectionObserver
函数:
✨核心单词解释:
useIntersectionObserver
检查元素是否进入可视区函数target
目标元素,🎯需配合模板 ref 使用isIntersecting
是否进入可视区(布尔值)stop
用于停止检测的函数
<script setup lang="ts">
import { ref } from 'vue';
import { useIntersectionObserver } from '@vueuse/core';
// 准备目标元素(DOM节点或组件,需配合模板 ref 使用)
const target = ref(null);
const { stop } = useIntersectionObserver(target, ([{ isIntersecting }]) => {
console.log('检测元素可见性', isIntersecting);
// 需求:如果目标元素进入可视区,就发送请求,并停止检测
if (isIntersecting) {
// 当目标元素进入可视区域时,才发送请求
console.log('进入可视区,需要发送请求');
// 请求已发送,主动停止检查
stop();
}
});
</script>
<template>
<div style="height: 2000px"></div>
<!-- 🎯目标元素需添加模板 ref -->
<div ref="target">
<h1>🎯我是目标元素🎯</h1>
</div>
<div style="height: 2000px"></div>
</template>
组件数据懒加载逻辑复用
本节目标:
抽离组件数据懒加载可复用的逻辑
现存问题
首页中,很多地方都应该使用组件数据懒加载这个功能,不管是哪个模块使用,下面代码都会重复书写。
事实上,唯一可能会随着业务使用发生变化的是 ajax接口的调用,其余的部分我们进行重复使用,抽离为可复用逻辑
抽离通用逻辑
1)抽离逻辑
src/hooks/index.ts
- hooks.ts 封装常用的 组合式 API 函数
import { useIntersectionObserver } from "@vueuse/core";
import { ref } from "vue";
/**
* 请求按需加载
* @param apiFn 发送请求函数
* @returns 🚨 target 用于模板绑定
*/
export const useObserver = (apiFn: () => void) => {
// 准备个 ref 用于绑定模板中的某个目标元素(DOM节点或组件)
const target = ref(null);
const { stop } = useIntersectionObserver(target, ([{ isIntersecting }]) => {
console.log("是否进入可视区域", isIntersecting);
if (isIntersecting) {
// 当目标元素进入可视区域时,才发送请求
apiFn();
// 请求已发送,主动停止检查
stop();
}
});
// 🚨返回 ref 用于模板绑定,建议返回对象格式支持解构获取
return { target };
};
2)业务改写
<script setup lang="ts">
import { RouterLink } from "vue-router";
import useStore from "@/store";
import HomePanel from "./home-panel.vue";
+import { useObserver } from "@/hooks";
const { home } = useStore();
+const { target } = useObserver(home.getHotGoodsList);
</script>