Vue项目---懒加载的应用

懒加载

介绍

懒加载(Lazy Loading)是一种常见的前端优化技术,用于延迟加载页面上的资源(如图片、视频、组件等),直到它们真正需要被显示时才加载。这种技术可以显著提高页面的加载速度,减少初始加载时的资源消耗,提升用户体验。

原理

懒加载的核心思想是:只加载用户当前需要的内容。例如,当用户滚动到页面的某个部分时,才加载该部分的图片或组件,而不是在页面加载时一次性加载所有内容。

展示

  • 我们可以在控制台看到一旦底部红色容器进入用户的窗口,那么就会触发懒加载机制,这里我设置了触发一次加载4个数据

详细解析

模版部分

  • 这里我应用了Element-Plus组件库中的Card组件。
  • <h2>vue懒加载</h2>:页面标题。
  • <el-card>:使用 Element Plus 的 el-card 组件来显示数据。
  • v-for 指令用于循环渲染 visibleResult 中的每一项数据。:key="item.title":为每个 el-card 设置唯一的 key,通常使用数据的唯一标识符(如 id 或 title)。
    <template #header>:定义卡片的头部,显示 item.title。
  • <p>:显示 item.description。
  • <div ref="obserRef" style="height: 100px; width: 100px; background: red"></div>:这是一个占位符元素,用于触发懒加载逻辑。当这个元素进入视口时,会触发加载更多数据的操作。
html 复制代码
<template>
  <div id="app-lazyload">
    <h2>vue懒加载</h2>
    <el-card
      v-for="item in visibleResult"
      :key="item.title"
      style="width: 500px; margin-top: 30px"
    >
      <template #header>
        <div class="标题">
          <span>{{ item.title }}</span>
        </div>
      </template>
      <p>
        {{ item.description }}
      </p>
      <template #footer></template>
    </el-card>
    <div
      ref="obserRef"
      style="height: 100px; width: 100px; background: red"
    ></div>
  </div>
</template>

脚本部分

数据和变量

  • data:从 .../data/data.json 导入的初始数据。
  • result:存储所有数据的响应式引用。
  • obserRef:通过 ref 创建的响应式引用,指向页面中的占位符元素。
  • visibleResult:存储当前已加载并显示在页面上的数据。

IntersectionObserver

observer:创建一个 IntersectionObserver 实例,用于监听占位符元素是否进入视口。
entries.forEach((entry) => { ... }):遍历所有被观察的元素。
entry.isIntersecting:判断当前元素是否进入视口。
visibleResult.value.length < result.value.length:确保还有更多数据可以加载。
loadMoreData():调用加载更多数据的函数。

加载更多数据

loadMoreData:从 result 中获取更多数据并添加到 visibleResult 中。
result.value.slice(visibleResult.value.length, visibleResult.value.length + 4):每次加载 4 条数据。
visibleResult.value.push(...newData):将新数据添加到 visibleResult 中。

生命周期钩子

onMounted

loadMoreData():组件挂载时,先加载一部分数据。

observer.observe(obserRef.value):开始监听占位符元素。
onUnmounted

observer.disconnect():组件卸载时,停止监听占位符元素,避免内存泄漏。

ts 复制代码
import data from "../data/data.json";
import { ref, onMounted, onUnmounted } from "vue";
interface Data {
  title: string;
  dispriation: string;
}
const result = ref<Data[]>(data);
//监听容器DOM
const obserRef = ref(null);
//窗口内数据
const visibleResult = ref<Data[]>([]);

//懒加载逻辑
const observer = new IntersectionObserver((entires) => {
  entires.forEach((entry) => {
    if (
      entry.isIntersecting &&
      visibleResult.value.length < result.value.length
    ) {
      //触发容器进入视图
      //获取数据
      loadMoreData();
    }
  });
});

//加载更多数据
const loadMoreData = () => {
  console.log("懒加载触发了");
  //有数据加载,一回加载3个数据
  const newData = result.value.slice(
    visibleResult.value.length,
    visibleResult.value.length + 4
  );
  visibleResult.value.push(...newData);
};

//初始化加载
onMounted(() => {
  loadMoreData();
  //监听容器
  observer.observe(obserRef.value);
});

//卸载observer
onUnmounted(() => {
  observer.disconnect();
});

代码

Mock数据

json 复制代码
[
  {
    "title": "熊出没",
    "description": "保护森林,熊熊有责"
  },
  {
    "title": "小马宝莉",
    "description": "奇幻冒险,传递友谊与勇气"
  },
  {
    "title": "巴巴爸爸",
    "description": "温馨家庭,奇妙变形冒险"
  },
  {
    "title": "虹猫蓝兔",
    "description": "武侠情怀,传递正义勇敢"
  },
  {
    "title": "花园宝宝",
    "description": "奇幻花园,启蒙认知与想象"
  },
  {
    "title": "天线宝宝",
    "description": "欢乐互动,陪伴幼儿成长"
  },
  {
    "title": "米老鼠和唐老鸭",
    "description": "经典形象,带来欢乐时光"
  },
  {
    "title": "哆啦A梦",
    "description": "神奇道具,开启奇幻之旅"
  },
  {
    "title": "奥特曼",
    "description": "光之巨人,守护地球和平"
  },
  {
    "title": "成龙历险记",
    "description": "环球冒险,收集神秘符咒"
  },
  {
    "title": "成龙历险记之魔法 Cookbook",
    "description": "美食魔法,开启奇幻旅程"
  },
  {
    "title": "海底小纵队",
    "description": "探索海底,保护海洋生物"
  },
  {
    "title": "大头儿子小头爸爸",
    "description": "温馨家庭,快乐成长"
  },
  {
    "title": "喜羊羊与灰太狼",
    "description": "斗智斗勇,欢乐不断"
  },
  {
    "title": "蓝猫龙骑团",
    "description": "勇敢冒险,守护和平"
  },
  {
    "title": "猫和老鼠",
    "description": "追逐打闹,欢乐无穷"
  },
  {
    "title": "黑猫警长",
    "description": "惩恶扬善,守护城市安全"
  },
  {
    "title": "熊熊乐园",
    "description": "寓教于乐,陪伴快乐童年"
  },
  {
    "title": "超级飞侠",
    "description": "环游世界,传递爱心与勇气"
  },
  {
    "title": "小猪佩奇",
    "description": "温馨日常,分享家庭欢乐"
  },
  {
    "title": "大耳朵图图",
    "description": "成长故事,充满童真童趣"
  },
  {
    "title": "开心宝贝",
    "description": "机智勇敢,守护地球和平"
  },
  {
    "title": "喜羊羊与灰太狼之勇闯四季城",
    "description": "四季冒险,展现智慧与力量"
  },
  {
    "title": "海绵宝宝",
    "description": "海底奇遇,带来无尽欢笑"
  },
  {
    "title": "名侦探柯南",
    "description": "解谜破案,维护正义"
  },
  {
    "title": "火影忍者",
    "description": "忍道精神,追逐梦想"
  }
]

前端代码

  • 这里为.vue文件
js 复制代码
<template>
  <div id="app-lazyload">
    <h2>vue懒加载</h2>
    <el-card
      v-for="item in visibleResult"
      :key="item.title"
      style="width: 500px; margin-top: 30px"
    >
      <template #header>
        <div class="标题">
          <span>{{ item.title }}</span>
        </div>
      </template>
      <p>
        {{ item.description }}
      </p>
      <template #footer></template>
    </el-card>
    <div
      ref="obserRef"
      style="height: 100px; width: 100px; background: red"
    ></div>
  </div>
</template>

<script setup lang="ts">
import data from "../data/data.json";
import { ref, onMounted, onUnmounted } from "vue";
interface Data {
  title: string;
  dispriation: string;
}
const result = ref<Data[]>(data);
//监听容器DOM
const obserRef = ref(null);
//窗口内数据
const visibleResult = ref<Data[]>([]);

//懒加载逻辑
const observer = new IntersectionObserver((entires) => {
  entires.forEach((entry) => {
    if (
      entry.isIntersecting &&
      visibleResult.value.length < result.value.length
    ) {
      //触发容器进入视图
      //获取数据
      loadMoreData();
    }
  });
});

//加载更多数据
const loadMoreData = () => {
  console.log("懒加载触发了");
  //有数据加载,一回加载3个数据
  const newData = result.value.slice(
    visibleResult.value.length,
    visibleResult.value.length + 4
  );
  visibleResult.value.push(...newData);
};

//初始化加载
onMounted(() => {
  loadMoreData();
  //监听容器
  observer.observe(obserRef.value);
});

//卸载observer
onUnmounted(() => {
  observer.disconnect();
});
</script>

<style scoped>
#app-lazyload {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}
</style>
相关推荐
qq_25183645734 分钟前
SpringBoot+Vue 共享电池柜管理系统 完整实现 前后端分离项目实战 完整代码
vue.js·spring boot·后端
摆烂大大王1 小时前
玩转 OpenClaw:用 TaskFlow + Heartbeat 打造自动化工作流
前端·人工智能·自动化
zhangxingchao1 小时前
AI 大模型核心六:量化、Workflow 与 Agent、多轮 RAG
前端·人工智能·后端
梦想的颜色1 小时前
TypeScript 完全指南(上):从零开始掌握类型系统
前端·typescript
之歆1 小时前
Day01_ES6+ 专业指南:从基础到实战的现代JavaScript开发(下)
前端·javascript·es6
lichenyang4532 小时前
鸿蒙 MVVM 实战:从 Demo 到工程化,聊聊登录、状态管理与埋点系统设计
前端
IT_陈寒2 小时前
Vite打包时遇到的坑,原来问题出在这里
前端·人工智能·后端
kyriewen2 小时前
AI生成代码快如闪电,但我修了三个小时——它到底帮了谁?
前端·javascript·ai编程
竹林8183 小时前
用 wagmi v2 和 viem 手写 NFT 市场批量上架功能,我踩遍了所有异步坑
javascript
ayqy贾杰3 小时前
基层管理的三板斧,在AI时代行不通了
前端·后端·团队管理