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>
相关推荐
崔庆才丨静觅4 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60615 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅6 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅6 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment6 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅6 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊6 小时前
jwt介绍
前端
爱敲代码的小鱼7 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax