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>
相关推荐
t_hj3 分钟前
Ajax案例
前端·javascript·ajax
bigHead-25 分钟前
9. 从《蜀道难》学CSS基础:三种选择器的实战解析
前端·css
阿里小阿希1 小时前
解决 pnpm dev 运行报错的坎坷历程
前端·node.js
未脱发程序员1 小时前
分享一款开源的图片去重软件 ImageContrastTools,基于Electron和hash算法
前端·javascript·electron
光电大美美-见合八方中国芯1 小时前
【平面波导外腔激光器专题系列】1064nm单纵模平面波导外腔激光器‌
网络·数据库·人工智能·算法·平面·性能优化
geovindu2 小时前
vue3: pdf.js 2.16.105 using typescript
javascript·vue.js·typescript·pdf
视频砖家2 小时前
Web前端VSCode如何解决打开html页面中文乱码的问题(方法2)
前端·vscode·vscode乱码·vscode中文乱码·vscode中文编码
2401_837088502 小时前
CSS transition过渡属性
前端·css
我爱吃朱肉2 小时前
深入理解 CSS Flex 布局:代码实例解析
前端·css
喝养乐多长不高2 小时前
Spring Web MVC基础理论和使用
java·前端·后端·spring·mvc·springmvc