懒加载和预加载和楼层式加载

懒加载的实现方式

懒加载的实现主要通过监听用户行为(如滚动触发事件)来判断何时加载内容。常见的实现方法有:

1. 使用 IntersectionObserver 实现懒加载(现代浏览器)

IntersectionObserver 是一个现代浏览器的 API,用于异步检测目标元素是否进入视口(viewport)。这是最推荐的懒加载实现方式,因为它高效且无需频繁监听滚动事件。

示例:图片懒加载

HTML:

ini 复制代码
html
复制代码
<img class="lazy" data-src="image1.jpg" alt="Lazy image 1" />
<img class="lazy" data-src="image2.jpg" alt="Lazy image 2" />
<img class="lazy" data-src="image3.jpg" alt="Lazy image 3" />

CSS:

css 复制代码
css
复制代码
.lazy {
  opacity: 0;
  transition: opacity 0.5s;
}
.lazy.loaded {
  opacity: 1;
}

JavaScript:

javascript 复制代码
javascript
复制代码
document.addEventListener("DOMContentLoaded", function() {
  const lazyImages = document.querySelectorAll('.lazy'); // 选择所有懒加载的图片

  if ('IntersectionObserver' in window) {
    const imageObserver = new IntersectionObserver((entries, observer) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const img = entry.target;
          img.src = img.dataset.src; // 加载图片
          img.classList.add('loaded'); // 图片加载完后显示
          observer.unobserve(img); // 停止观察已加载的图片
        }
      });
    });

    lazyImages.forEach(image => {
      imageObserver.observe(image); // 对每个图片进行观察
    });
  } else {
    // 如果不支持 IntersectionObserver, 退回到滚动事件监听方案
    console.log("IntersectionObserver not supported.");
  }
});
2. 使用 scroll 事件实现懒加载(旧浏览器)

对于不支持 IntersectionObserver 的旧浏览器(如 IE),可以通过监听 scroll 事件并手动检测元素是否进入视口来实现懒加载。

示例:图片懒加载

JavaScript:

javascript 复制代码
javascript
复制代码
function isElementInViewport(el) {
  const rect = el.getBoundingClientRect();
  return (
    rect.top >= 0 &&
    rect.left >= 0 &&
    rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
    rect.right <= (window.innerWidth || document.documentElement.clientWidth)
  );
}

function lazyLoad() {
  const lazyImages = document.querySelectorAll('.lazy');
  lazyImages.forEach(img => {
    if (isElementInViewport(img)) {
      img.src = img.dataset.src;
      img.classList.add('loaded'); // 图片加载完后显示
    }
  });

  // 如果所有图片都加载完了,可以移除滚动事件监听
  if (document.querySelectorAll('.lazy:not(.loaded)').length === 0) {
    window.removeEventListener('scroll', lazyLoad);
  }
}

window.addEventListener('scroll', lazyLoad);
window.addEventListener('resize', lazyLoad); // 处理窗口调整时的加载
优化:使用节流(Throttle)技术

使用 scroll 事件时,滚动操作会触发非常频繁的回调,可能影响性能。因此,可以通过节流(throttle)技术来减少回调的频率。

javascript 复制代码
javascript
复制代码
function throttle(fn, wait) {
  let time = Date.now();
  return function() {
    if ((time + wait - Date.now()) < 0) {
      fn();
      time = Date.now();
    }
  };
}

window.addEventListener('scroll', throttle(lazyLoad, 200)); // 每200ms触发一次lazyLoad
3. <img loading="lazy"> 属性(原生图片懒加载)

最新的 HTML 标准中提供了一个内置的懒加载属性 loading="lazy",可以为 <img><iframe> 元素开启懒加载,无需使用 JavaScript。这是实现懒加载的最简单方法,前提是浏览器支持该特性。

示例:
ini 复制代码
html
复制代码
<img src="image1.jpg" loading="lazy" alt="Lazy image" />

这种方式非常简洁,不过浏览器的支持情况还不完全一致,目前较新的版本的 Chrome、Firefox 等支持这一特性。

4. 模块懒加载(代码拆分)

在现代的 JavaScript 应用(特别是单页面应用中),懒加载不仅可以用于资源(如图片、视频),还可以用于代码模块。通过 Webpack 等打包工具,你可以按需加载代码模块,这样初始页面只加载必要的部分,其他部分在需要时加载。

示例:使用 Webpack 实现模块懒加载
javascript 复制代码
javascript
复制代码
// 某个按钮点击时,才加载某个模块
document.getElementById('loadModuleBtn').addEventListener('click', () => {
  import('./someModule.js').then(module => {
    // 动态加载模块后执行相关操作
    module.doSomething();
  });
});

Webpack 内部会根据 import()someModule.js 拆分成单独的文件,并且在需要的时候按需加载它。

懒加载的应用场景

  1. 图片懒加载:大型图片集、瀑布流布局、图片画廊等场景使用懒加载,减少初始页面加载时间。
  2. 视频/音频懒加载:当用户滚动到视频或音频所在区域时再加载,减少初始带宽消耗。
  3. 模块懒加载:在单页面应用(SPA)中,按需加载 JavaScript 模块,减少初始打包体积,提升首屏性能。
  4. 广告懒加载:广告通常是外部资源,懒加载可以减少对页面的影响,并优化广告展示效果。
  5. 表单或其他资源懒加载:当页面中有多步骤表单时,可以只加载当前步骤的表单元素,其他部分在用户需要时再加载。

懒加载的优点

  • 提升页面性能:懒加载可以减少页面初次加载时的资源数量,加快首屏展示速度,改善用户体验。
  • 减少带宽消耗:只加载用户实际会看到的资源,避免加载多余的内容。
  • 优化大数据场景:对于有大量数据或图像的页面(如电商、社交媒体),懒加载非常有效。

懒加载的缺点

  • 延迟显示:当用户快速滚动到懒加载的内容时,可能会出现短暂的加载延迟,内容需要等异步加载完成后才显示。
  • SEO 影响:如果搜索引擎爬虫无法执行 JavaScript,懒加载的内容可能不会被爬取。但现代搜索引擎对懒加载支持越来越好,影响减小。

总结

懒加载是一种重要的前端优化技术,能有效提升页面的加载性能和用户体验。通过 IntersectionObserver 可以实现高效的懒加载,而在旧版浏览器中则可以通过 scroll 事件实现。同时,HTML5 提供了 <img loading="lazy"> 属性,简化了图片懒加载的实现。无论是图片、视频,还是 JavaScript 模块,懒加载的思路都是按需加载,避免一次性加载过多内容。

4o

您说:

在vue项目中使用模块懒加载

ChatGPT 说:

ChatGPT

在 Vue 项目中,模块懒加载可以通过动态导入和 Vue 路由的异步组件加载实现。懒加载的核心是按需加载 JavaScript 模块,而不是在页面加载时一次性加载所有模块,从而优化页面性能和用户体验。

以下是如何在 Vue 项目中实现模块懒加载的几个常见场景:

1. 路由懒加载

Vue Router 支持通过动态导入的方式实现路由组件的懒加载。这样,只有当用户访问某个路由时,才会加载对应的组件文件,而不是在应用初始化时就加载所有路由的组件。

实现步骤:

假设我们有一个典型的 Vue 项目,其中 HomeAbout 是两个页面,通常你会在路由配置中静态导入组件,如下:

javascript 复制代码
javascript
复制代码
import Home from '@/components/Home.vue';
import About from '@/components/About.vue';

export const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
];

实现懒加载的方式

通过使用 Webpack 提供的 import() 函数,进行动态导入:

javascript 复制代码
javascript
复制代码
export const routes = [
  {
    path: '/',
    name: 'Home',
    component: () => import('@/components/Home.vue'),  // 懒加载Home组件
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('@/components/About.vue'), // 懒加载About组件
  },
];
原理:
  • Webpack 会将每个懒加载的模块打包成一个单独的文件(称为代码分块),这些文件只有在用户访问相应路由时才会被加载。
  • 使用 import() 返回一个 Promise,在需要加载组件时动态请求该模块。

2. 组件懒加载

在 Vue 中,你可以按需加载某些组件,而不是在页面加载时一次性加载所有组件。通常你会在大型应用或具有重型组件(如表格、图表等)时使用这个功能。

示例:
xml 复制代码
vue
复制代码
<template>
  <div>
    <h1>Lazy Loading Example</h1>
    <button @click="showComponent = true">加载组件</button>
    <!-- 使用v-if控制懒加载的组件 -->
    <LazyLoadedComponent v-if="showComponent" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      showComponent: false,
    };
  },
  components: {
    LazyLoadedComponent: () => import('@/components/HeavyComponent.vue') // 懒加载组件
  }
};
</script>
解释:
  • 这里我们在 components 选项中使用 import() 函数来动态导入 HeavyComponent.vue,这是一个较重的组件。
  • v-if="showComponent" 控制只有在用户点击按钮时才显示并加载组件,这样可以避免在页面加载时立即加载这个组件。

3. 按需加载 Vuex 模块

在大型应用中,你可能不需要一次性注册所有的 Vuex 模块。可以在某些组件加载时,动态注册 Vuex 模块。

示例:
javascript 复制代码
javascript
复制代码
// store/modules/myModule.js
export default {
  namespaced: true,
  state: {
    count: 0,
  },
  mutations: {
    increment(state) {
      state.count++;
    },
  },
};

// 在某个组件中动态注册 Vuex 模块
export default {
  created() {
    if (!this.$store.hasModule('myModule')) {
      import('@/store/modules/myModule').then(module => {
        this.$store.registerModule('myModule', module.default);
      });
    }
  },
  methods: {
    increment() {
      this.$store.commit('myModule/increment');
    },
  },
};
解释:
  • 在组件创建时,检查是否已经注册了 myModule 模块。如果未注册,则动态加载并注册该 Vuex 模块。
  • 这种方式可以避免初始加载时导入不必要的 Vuex 模块,从而减少应用的初始包大小。

4. 使用 webpackChunkName 为懒加载模块命名

当你在生产环境中使用 Webpack 懒加载时,默认情况下会生成类似 0.js, 1.js 等匿名文件。如果你想要对这些文件进行更友好的命名,可以通过 webpackChunkName 给每个懒加载模块命名。

示例:
javascript 复制代码
javascript
复制代码
export const routes = [
  {
    path: '/',
    name: 'Home',
    component: () => import(/* webpackChunkName: "home" */ '@/components/Home.vue'),
  },
  {
    path: '/about',
    name: 'About',
    component: () => import(/* webpackChunkName: "about" */ '@/components/About.vue'),
  },
];
解释:
  • Webpack 会将生成的懒加载文件命名为 home.jsabout.js,而不是匿名的数字命名,方便调试和识别。

5. 预加载(Preload)与预获取(Prefetch)

除了懒加载,Vue 和 Webpack 还支持预加载预获取技术,帮助你进一步优化资源加载策略。

  • 预加载(Preload) :资源会在父模块加载后立即加载,但其优先级较高,适合页面加载后马上会用到的资源。
  • 预获取(Prefetch) :资源会在浏览器空闲时加载,适合未来可能会用到但不紧急的资源。
使用方式:
javascript 复制代码
javascript
复制代码
// Preload 用法
component: () => import(/* webpackPrefetch: true */ '@/components/About.vue')

// Prefetch 用法
component: () => import(/* webpackPreload: true */ '@/components/Home.vue')
解释:
  • PreloadPrefetch 提供了更灵活的资源加载策略,允许你提前加载即将使用的模块,而不影响首屏性能。

预加载 (Preload)是一种优化网页资源加载的技术,允许浏览器在加载页面的关键资源(如 CSS 和 JavaScript)时,提前加载将要用到的资源。预加载的资源具有较高的优先级,它们会在关键资源加载之后立即开始加载,但不会阻塞关键资源的渲染。

预加载通常用于优化首屏性能,确保关键资源在渲染页面时已经被提前加载,从而减少页面加载时间。

在 Web 项目中,预加载有几种常见的实现方式:

为了优化首屏加载性能,我们可以通过按需加载首屏资源,推迟或懒加载那些不需要立即展示的资源。这种策略可以减少首屏加载时的资源开销,确保用户更快看到页面内容,提升用户体验。

实现首屏只加载需要资源的策略主要有以下几种方法:

1. 路由懒加载(模块按需加载)

在使用单页面应用(SPA)时,比如在 Vue.js 或 React.js 项目中,通常会通过路由系统来切换页面。在首屏渲染时,我们可以通过动态加载非首屏的页面组件,避免一次性加载整个应用的所有页面资源。

Vue.js 中的懒加载:
javascript 复制代码
javascript
复制代码
// 使用 Vue Router 的路由懒加载
const router = new VueRouter({
  routes: [
    {
      path: '/home',
      component: () => import('@/views/Home.vue') // 只在访问时才加载该组件
    },
    {
      path: '/about',
      component: () => import('@/views/About.vue') // 延迟加载,用户访问时才加载
    }
  ]
});
React.js 中的懒加载:
javascript 复制代码
javascript
复制代码
import React, { lazy, Suspense } from 'react';

const Home = lazy(() => import('./Home')); // 首屏页面
const About = lazy(() => import('./About')); // 延迟加载页面

function App() {
  return (
    <Router>
      <Suspense fallback={<div>Loading...</div>}>
        <Switch>
          <Route path="/home" component={Home} />
          <Route path="/about" component={About} />
        </Switch>
      </Suspense>
    </Router>
  );
}

通过路由懒加载,只有当前页面的资源会被加载,而其他页面的组件则在用户导航到对应页面时动态加载。

2. 按需加载 CSS 和 JavaScript

首屏渲染时,我们可以通过按需加载 CSS 和 JavaScript,避免加载整个应用的样式和脚本。可以使用 Webpack 的 splitChunks 进行代码拆分,或者通过动态加载资源的方式控制加载顺序。

动态加载 JavaScript:
javascript 复制代码
javascript
复制代码
// 只在需要时加载某个脚本
function loadScript(url) {
  const script = document.createElement('script');
  script.src = url;
  document.body.appendChild(script);
}

window.addEventListener('DOMContentLoaded', () => {
  loadScript('/path/to/other-script.js'); // 页面加载完成后再加载
});
动态加载 CSS:
ini 复制代码
javascript
复制代码
// 只在需要时加载某个样式文件
function loadCSS(url) {
  const link = document.createElement('link');
  link.rel = 'stylesheet';
  link.href = url;
  document.head.appendChild(link);
}

window.addEventListener('DOMContentLoaded', () => {
  loadCSS('/path/to/other-styles.css'); // 页面加载完成后再加载样式
});

通过动态加载脚本和样式文件,可以只在页面需要时加载额外资源,避免首屏加载过多资源。

3. 图片懒加载

对于首屏不显示的图片,可以使用懒加载技术,即在图片进入视口时才进行加载。这不仅减少了首屏加载的资源,还能减少带宽消耗。

使用 IntersectionObserver 实现懒加载图片:
ini 复制代码
html
复制代码
<img class="lazy" data-src="image1.jpg" alt="Lazy Image 1">
<img class="lazy" data-src="image2.jpg" alt="Lazy Image 2">
ini 复制代码
javascript
复制代码
document.addEventListener("DOMContentLoaded", function() {
  const lazyImages = document.querySelectorAll('.lazy');
  const imageObserver = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target;
        img.src = img.dataset.src; // 加载图片
        observer.unobserve(img);   // 停止观察已加载的图片
      }
    });
  });
  lazyImages.forEach(image => imageObserver.observe(image));
});

4. 资源预加载和预获取

对于首屏渲染中马上会用到的资源,可以使用预加载(preload)来加快加载速度,而对于稍后可能需要的资源,则可以使用预获取(prefetch) ,在空闲时加载。

预加载 CSS、JS 或字体:
ini 复制代码
html
复制代码
<link rel="preload" href="/path/to/styles.css" as="style">
<link rel="preload" href="/path/to/script.js" as="script">
<link rel="preload" href="/path/to/font.woff2" as="font" type="font/woff2" crossorigin="anonymous">
预获取非关键资源:
ini 复制代码
html
复制代码
<link rel="prefetch" href="/path/to/large-image.jpg" as="image">
<link rel="prefetch" href="/path/to/secondary-page.js" as="script">

在 HTML 中,你可以使用 <link rel="preload"> 标签来实现资源的预加载。这个标签告诉浏览器,某个资源(如 JavaScript、CSS、字体、图片等)是即将使用的,应该尽早加载。

示例:
ini 复制代码
html
复制代码
<link rel="preload" href="/styles/main.css" as="style">
<link rel="preload" href="/scripts/main.js" as="script">
<link rel="preload" href="/images/banner.jpg" as="image">
解释:
  • href:要预加载的资源路径。
  • as :指定资源的类型,这有助于浏览器正确地管理资源优先级。常见的值有 style(CSS 文件)、script(JavaScript 文件)、image(图片)、font(字体)等。

字体文件也是常见的预加载对象。特别是在页面加载时,需要快速显示文本的场景,提前加载字体可以避免 "FOIT"(Flash of Invisible Text,闪烁的不可见文字)问题。

示例:
bash 复制代码
html
复制代码
<link rel="preload" href="/fonts/my-font.woff2" as="font" type="font/woff2" crossorigin="anonymous">
解释:
  • type="font/woff2" :指定字体文件的格式。
  • crossorigin="anonymous" :对于跨域的字体请求,设置 crossorigin 属性,确保浏览器能够正确地加载该资源。

3. 使用 Webpack 的 Preload 插件

在使用 Webpack 时,你可以通过动态导入 JavaScript 模块,同时为某些模块添加预加载功能。这可以确保在当前模块加载时,预加载未来可能用到的模块,以便用户需要时快速加载。

Webpack 提供了 PreloadPrefetch 注释,分别用于加载即将用到的资源和可能未来用到的资源。

使用 Webpack 实现预加载

假设你在 Vue 项目或 React 项目中使用 Webpack,你可以通过 import() 来动态加载模块,并添加预加载注释:

java 复制代码
javascript
复制代码
// Preload example: 该模块会在父模块加载后立即加载
import(/* webpackPreload: true */ './myComponent.js').then(module => {
  // 使用加载后的模块
  module.default();
});
解释:
  • /* webpackPreload: true */ :这是 Webpack 的魔法注释,告诉 Webpack 要预加载这个模块。在加载当前模块的同时,浏览器会优先加载这个预加载的模块,以便在稍后更快地使用。

为了实现页面上使用 MD5 值来判断是否使用接口数据或缓存数据的功能,你需要遵循以下步骤:

楼层式加载

实现步骤概述:

  1. 请求数据并生成 MD5 哈希值:请求接口数据后,对数据内容生成 MD5 哈希值。
  2. 缓存数据与 MD5 :将数据和 MD5 哈希值一起存入缓存(比如 localStorage)。
  3. 判断是否使用缓存数据:在每次进入页面时,先检查缓存中的 MD5 值是否与接口返回的 MD5 匹配。如果匹配,则使用缓存数据;如果不匹配,则重新请求接口数据并更新缓存。
相关推荐
y先森35 分钟前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy36 分钟前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu108301891139 分钟前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿2 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡3 小时前
commitlint校验git提交信息
前端
虾球xz3 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇3 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒3 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员4 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐4 小时前
前端图像处理(一)
前端