vue3 懒加载组件 + 自定义hooks

news/2025/1/14 14:07:07/

背景

有一天我在逛淘宝的时候发现一个现象,就是淘宝pc 端的搜索列表页,在滚动的时候,它的那些图片总有一种从无到有的感觉,作为一个前端人,我就很好奇他是做了什么优化,是不是对元素做了懒加载处理。没进入视口的内容只做占位处理。于是我就检查了一下元素,果不其然,第一张图是列表第一个商品的dom结果,第二张图是列表中最后一个商品的dom,它还没有进入视口,所以只有一个高度为 260 的占位的 div 。 感兴趣的小伙伴也可以去淘宝上验证一下。
在这里插入图片描述
在这里插入图片描述

思考

我在想能不能把这个指令做得更通用一点,只处理图片好像有点局限性,我希望能做成一个对任何组件都能实现懒加载。

业务场景

  • 背景:由于我们的页面比较大,在一个页面上会加载比较多这样的模块,大致的样式看下图。
  • 问题:由于页面一加载,就会请求页面所需要的所有数据,往往一个页面所需要请求的数据,多达几十个,造成页面加载非常的缓慢。且我们都知道并不是先发出去的请求就会先回来,有时候遇到一些情况是这样的,下面的组件发出去的请求都回来了,但是视口的请求还没回来。导致没有意义的等待。
  • 处理方案

在这里插入图片描述

实现

Intersection Observer API

交叉观察器 API(Intersection Observer API)提供了一种异步检测目标元素与祖先元素或顶级文档的视口相交情况变化的方法。
具体的可以查看 MDN 文档 。这里头写的非常的清楚。简单地来说,我就可以通过这个api 来判断元素是否已经进入我们的视口。而且这个api 并不存在性能问题,所以大家可以放心使用。

自定义hooks useVisibilityHook

代码很简单,就是用于监听组件或者元素是否已经进入视口

import { ref, onMounted, onBeforeUnmount, watch } from "vue";const defaultConfig = {root: null,threshold: 0.2,rootMargin: "0px",
};export function useVisibility(options = {}, initialVisible = false) {const isVisible = ref(initialVisible);const element = ref(null);const observer = ref(null);onMounted(() => {// 初始化监听器observer.value = new IntersectionObserver(([entry]) => {if (entry.isIntersecting) {isVisible.value = true;observer.value.disconnect();}},{...defaultConfig,...options,});});watch(isVisible, (newVisible) => {if (newVisible) {isVisible.value = true;}});onMounted(() => {if (element.value) {observer.value.observe(element.value);}});onBeforeUnmount(() => {// 卸载的时候要注意 disconnectif (observer.value) {observer.value.disconnect();}});return {element,isVisible,};
}

封装懒加载组件

我们接触自定义的hooks useVisibilityHook 封装了下面这样的组件,由于我不想引入类似 ant-design-vue 这样的组件库,来增加复杂度,小伙伴们可以根据自己的需要来修改

<template><div :style="{ minHeight: '200px' }" ref="element"><template v-if="isVisible"><slot></slot></template><template v-else><!-- 使用具名插槽 fallback,提供默认内容 --><slot name="fallback">组件还未进入视口,组件进入视口后渲染...</slot></template></div>
</template><script>
import { defineComponent } from "vue";
import { useVisibility } from "../hooks/useVisibilityHook";export default defineComponent({props: {visible: {type: Boolean,default: false,},options: {type: Object,default: () => ({}),},},setup(props) {const { element, isVisible } = useVisibility(props.options, props.visible);return {element,isVisible,};},
});
</script>

总计

至此,我们的工作就做完了。我把代码放到 sandbox 中,方便大家直接预览效果


http://www.ppmy.cn/news/1563045.html

相关文章

安卓14无法安装应用解决历程

客户手机基本情况&#xff1a; 安卓14&#xff0c;对应的 targetSdkVersion 34 前天遇到了安卓14适配问题&#xff0c;客户发来的截图是这样的 描述&#xff1a;无法安装我们公司的B应用。 型号&#xff1a;三星google美版 解决步骤&#xff1a; 1、寻找其他安卓14手机测试…

Excel多层嵌套IF条件写法

Excel多层嵌套IF条件的实现方法 需求如下 利润 > 35% 卖价 成本 *&#xff08;1-毛利0.15&#xff09;利润 < 35% 并 >0.34 卖价 成本 *&#xff08;1-毛利0.14&#xff09;利润 < 34% 并 >0.33 卖价 成本 *&#xff08;1-毛利0.13&#xff09;利润 < 33% …

Keep-Alive功能的抓包分析测试

成功的抓包 如图&#xff0c;间隔30秒 问:你还在吗 1501 56.502616 192.168.5.105 58683 192.168.5.25 8848 TCP 55 02:50:48.155738 [TCP Keep-Alive] 58683 → 8848 [ACK] Seq344 Ack1679196 Win131072 Len1 答&#xff1a;在 1502 56.503982…

项目概述、开发环境搭建(day01)

软件开发整体介绍 软件开发流程 第1阶段: 需求分析 需求规格说明书&#xff0c; 一般来说就是使用 Word 文档来描述当前项目的各个组成部分&#xff0c;如&#xff1a;系统定义、应用环境、功能规格、性能需求等&#xff0c;都会在文档中描述。产品原型&#xff0c;一般是通过…

jeecg-boot 表单选择一条数据保存

HTML&#xff08;新增form&#xff09; <a-col :span"24"><a-form-item label"专题学习表名称" :labelCol"labelCol" :wrapperCol"wrapperCol"><!-- <a-input v-decorator"[studyName, validatorRules.studyN…

查看nginx已安装的模块

一、查看nginx已经安装了哪些模块 1、使用nginx -V [rootjxq-c2-16-1 auto]# /alidata/nginx/sbin/nginx -V nginx version: nginx/1.11.13 built by gcc 4.4.7 20120313 (Red Hat 4.4.7-17) (GCC) built with OpenSSL 1.0.1e-fips 11 Feb 2013 TLS SNI support enabled conf…

ImagePicker操作多张图片

文章目录 1. 概念介绍2. 方法与细节2.1 实现方法2.2 具体细节3. 示例代码4. 内容总结我们在上一章回中介绍了"如何选择单个图片文件"相关的内容,本章回中将介绍如何选择多个图片文件.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在上一章回中介绍了如何…

基于大语言模型的组合优化

摘要&#xff1a;组合优化&#xff08;Combinatorial Optimization, CO&#xff09;对于提高工程应用的效率和性能至关重要。随着问题规模的增大和依赖关系的复杂化&#xff0c;找到最优解变得极具挑战性。在处理现实世界的工程问题时&#xff0c;基于纯数学推理的算法存在局限…