MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Vue项目中懒加载的实现方式

2022-02-013.9k 阅读

什么是懒加载

懒加载,也称为延迟加载,在前端开发中是一种优化策略。它的核心思想是在需要的时候才加载资源,而不是在页面初始加载时就加载所有资源。对于 Vue 项目而言,这意味着组件、图片等资源只有在用户即将看到它们的时候才进行加载,从而提高页面的初始渲染速度,减少用户等待时间,提升用户体验。

在 Vue 应用里,可能会有许多组件,有些组件在页面初始化时并不需要马上展示,比如页面滚动到某个位置才出现的广告组件、详情页里折叠起来的附加信息组件等。如果一开始就加载这些组件,会增加页面的初始加载体积,导致首屏加载缓慢。懒加载就是解决这类问题的有效手段。

Vue 中懒加载的应用场景

  1. 组件懒加载
    • 大型单页应用:在大型 Vue 单页应用(SPA)中,页面可能包含大量的组件。例如,一个电商平台的商品详情页,除了基本的商品信息展示组件外,还有评论组件、相关推荐组件、店铺信息组件等。如果所有组件在页面加载时就被引入,会大大增加初始加载时间。通过组件懒加载,可以将不急需的组件延迟到需要时加载。比如评论组件,用户可能在查看完商品基本信息后才会去看评论,这时再加载评论组件就可以提升初始页面的加载速度。
    • 动态路由组件:Vue Router 常用于构建单页应用的路由系统。在动态路由配置中,不同的路由可能对应不同的组件。例如,一个后台管理系统,有用户管理、订单管理、商品管理等不同的路由页面。每个路由页面都是一个独立的组件。通过懒加载,可以在用户访问某个路由时才加载对应的组件,而不是在应用启动时就加载所有路由组件,有效减少初始加载包的大小。
  2. 图片懒加载
    • 图片列表页:在图片展示页面,如图片库或商品图片列表页,通常会有大量的图片。如果这些图片在页面加载时全部加载,不仅会消耗大量的网络带宽,还会导致页面加载缓慢。图片懒加载可以让图片在即将进入浏览器可视区域时才加载。比如一个瀑布流图片展示页面,用户不断滚动页面查看更多图片,懒加载可以保证只有当新图片即将出现在可视区域时才进行加载,避免一次性加载大量图片对性能的影响。
    • 自适应图片:对于响应式网页,不同设备可能需要加载不同尺寸的图片。例如,在移动端加载较小尺寸的图片,在桌面端加载较大尺寸的图片。结合懒加载,可以在设备确定展示图片时,根据设备屏幕尺寸等条件加载合适尺寸的图片,进一步优化加载性能。

Vue 中组件懒加载的实现方式

  1. Vue Router 动态导入(ES2020 动态 import)
    • 原理:ES2020 引入了动态 import() 语法,它返回一个 Promise。在 Vue Router 配置中,可以利用这个语法实现组件的懒加载。当路由被访问时,才会动态导入对应的组件,而不是在应用启动时就加载所有路由组件。
    • 代码示例
      • 首先,确保你的项目中安装了 vue-router。假设我们有一个简单的 Vue 项目结构,src/views 目录存放视图组件。
      • router/index.js 文件中配置路由:
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/home',
      name: 'Home',
      component: () => import('@/views/Home.vue')
    },
    {
      path: '/about',
      name: 'About',
      component: () => import('@/views/About.vue')
    }
  ]
})

export default router

在上述代码中,component 字段使用了箭头函数和动态 import。当用户访问 /home 路由时,才会加载 Home.vue 组件;访问 /about 路由时,才会加载 About.vue 组件。这样就实现了路由组件的懒加载,减少了应用初始加载时的代码体积。 2. Vue 异步组件(Vue 2.x 兼容性方式)

  • 原理:在 Vue 2.x 中,虽然没有 ES2020 动态 import 那样原生的支持,但 Vue 提供了 Vue.component 方法来定义异步组件。异步组件会在需要渲染时才加载。
  • 代码示例
    • 假设我们有一个 App.vue 文件,需要在其中引入一个异步组件 MyAsyncComponent
<template>
  <div id="app">
    <MyAsyncComponent />
  </div>
</template>

<script>
export default {
  components: {
    MyAsyncComponent: () => import('./components/MyAsyncComponent.vue')
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit - font - smoothing: antialiased;
  -moz - osx - font - smoothing: grayscale;
  text - align: center;
  color: #2c3e50;
  margin - top: 60px;
}
</style>

在上述代码中,通过在 components 选项中使用箭头函数和 import 来定义异步组件。MyAsyncComponent 组件在 App.vue 需要渲染它时才会加载。这种方式在 Vue 2.x 项目中是常用的组件懒加载手段,同时在 Vue 3.x 中也依然兼容。

图片懒加载的实现方式

  1. 使用 IntersectionObserver API
    • 原理IntersectionObserver API 是浏览器提供的用于异步观察目标元素与祖先元素或视口(viewport)交叉变化情况的 API。在图片懒加载场景中,我们可以利用它来观察图片元素是否即将进入视口。当图片元素即将进入视口(即与视口有交集)时,就触发图片的加载。
    • 代码示例
      • 首先,在 Vue 组件模板中定义一个图片元素,初始时设置 src 为一个占位符(比如一个 1x1 的透明图片),并给图片添加一个唯一的标识,比如 data - src 来存放真实的图片地址。
<template>
  <div>
    <img :data - src="imageUrl" alt="Lazy Loaded Image" ref="lazyImage" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      imageUrl: 'https://example.com/real - image.jpg'
    }
  },
  mounted() {
    const lazyImage = this.$refs.lazyImage
    const observer = new IntersectionObserver((entries, observer) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          lazyImage.src = lazyImage.dataset.src
          observer.unobserve(lazyImage)
        }
      })
    })
    observer.observe(lazyImage)
  }
}
</script>

在上述代码中,mounted 钩子函数在组件挂载后执行。通过 IntersectionObserver 观察 lazyImage 元素。当 lazyImage 与视口有交集(entry.isIntersectingtrue)时,将 data - src 的值赋给 src,从而加载真实图片,并停止观察。 2. 使用 vue - lazyload 插件

  • 原理vue - lazyload 是一个专门为 Vue 项目设计的图片懒加载插件。它基于 IntersectionObserver API 进行封装,并提供了更便捷的使用方式,同时还支持一些额外的功能,如加载动画、错误处理等。
  • 安装与使用
    • 首先安装插件:
npm install vue - lazyload --save
 - 然后在 Vue 项目的入口文件(通常是 `main.js`)中引入并使用插件:
import Vue from 'vue'
import VueLazyload from 'vue - lazyload'

Vue.use(VueLazyload, {
  preLoad: 1.3,
  error: 'https://example.com/error.jpg',
  loading: 'https://example.com/loading.gif',
  attempt: 3
})

在上述代码中,通过 Vue.use(VueLazyload) 来使用插件,并传入一些配置选项。preLoad 表示在距离视口多远时开始加载图片(倍数);error 表示图片加载失败时显示的图片地址;loading 表示图片加载过程中显示的加载动画图片地址;attempt 表示图片加载失败后的重试次数。 - 在 Vue 组件模板中使用:

<template>
  <div>
    <img v - lazy="imageUrl" alt="Lazy Loaded Image" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      imageUrl: 'https://example.com/real - image.jpg'
    }
  }
}
</script>

通过在 img 标签上使用 v - lazy 指令,vue - lazyload 插件会自动处理图片的懒加载逻辑,大大简化了代码编写。

懒加载的优化与注意事项

  1. 预加载优化
    • 组件预加载:虽然懒加载可以延迟组件的加载,但在某些情况下,我们可以提前预测用户的行为,进行组件的预加载。例如,在一个多步骤向导式的表单页面中,用户完成第一步后,在用户操作第二步的过程中,可以提前预加载第三步的组件。在 Vue Router 中,可以通过 router.beforeEach 钩子函数结合动态 import 来实现。假设我们有三个路由 /step1/step2/step3
import { createRouter, createWebHistory } from 'vue - router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/step1',
      name: 'Step1',
      component: () => import('@/views/Step1.vue')
    },
    {
      path: '/step2',
      name: 'Step2',
      component: () => import('@/views/Step2.vue')
    },
    {
      path: '/step3',
      name: 'Step3',
      component: () => import('@/views/Step3.vue')
    }
  ]
})

router.beforeEach((to, from, next) => {
  if (to.name === 'Step2' && from.name === 'Step1') {
    import('@/views/Step3.vue')
  }
  next()
})

export default router

在上述代码中,当用户从 Step1 路由跳转到 Step2 路由时,提前预加载 Step3.vue 组件,这样当用户真正跳转到 Step3 路由时,组件可以更快地显示出来。

  • 图片预加载:对于图片懒加载,vue - lazyload 插件中的 preLoad 配置项就是一种预加载的方式。通过调整 preLoad 的值(如设置为 1.3,表示在距离视口 1.3 倍图片高度时开始加载图片),可以优化图片加载时机,避免用户看到图片加载的闪烁。同时,也可以在页面空闲时,主动预加载一些关键图片。例如,在页面滚动结束且一定时间内没有新的滚动操作时,预加载下一批可能出现的图片。可以使用 requestIdleCallback(浏览器提供的在浏览器空闲时段执行低优先级任务的 API)结合 IntersectionObserver 来实现。
  1. 错误处理
    • 组件懒加载错误:在组件懒加载过程中,可能会因为网络问题、组件路径错误等原因导致加载失败。在使用 ES2020 动态 import 时,可以通过 .catch 方法捕获加载错误。例如,在 router/index.js 中:
import { createRouter, createWebHistory } from 'vue - router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/home',
      name: 'Home',
      component: () => import('@/views/Home.vue').catch(error => {
        console.error('Home component load error:', error)
        // 可以在这里返回一个错误提示组件
        return import('@/views/ErrorComponent.vue')
      })
    }
  ]
})

export default router

在上述代码中,如果 Home.vue 组件加载失败,会捕获错误并打印到控制台,同时返回一个 ErrorComponent.vue 组件给用户展示错误信息。

  • 图片懒加载错误vue - lazyload 插件提供了 error 配置项来处理图片加载失败的情况。当图片加载失败时,会显示配置的错误图片。如果需要更详细的错误处理,比如记录错误日志,可以在 IntersectionObserver 的回调函数中添加错误处理逻辑。例如:
<template>
  <div>
    <img :data - src="imageUrl" alt="Lazy Loaded Image" ref="lazyImage" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      imageUrl: 'https://example.com/real - image.jpg'
    }
  },
  mounted() {
    const lazyImage = this.$refs.lazyImage
    const observer = new IntersectionObserver((entries, observer) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          lazyImage.src = lazyImage.dataset.src
          lazyImage.onerror = () => {
            console.error('Image load error')
            // 可以在这里显示自定义错误提示
          }
          observer.unobserve(lazyImage)
        }
      })
    })
    observer.observe(lazyImage)
  }
}
</script>
  1. SEO 考虑
    • 组件懒加载与 SEO:对于搜索引擎爬虫来说,懒加载的组件可能不会被正常抓取。如果页面中的关键内容放在懒加载组件中,可能会影响网站的搜索引擎排名。解决方法之一是使用服务器端渲染(SSR)。在 SSR 场景下,服务器会在渲染页面时将懒加载组件的内容也一并渲染出来,这样搜索引擎爬虫可以正常抓取到所有内容。例如,使用 Nuxt.js(基于 Vue 的服务器端渲染框架),可以方便地实现 SSR。在 Nuxt.js 项目中,即使使用了组件懒加载,服务器端渲染也能保证页面内容对搜索引擎友好。
    • 图片懒加载与 SEO:搜索引擎爬虫通常不会执行 JavaScript,所以图片懒加载可能导致图片无法被正确抓取。一种解决方法是在页面初始加载时,对于重要的图片(如文章中的关键图片、产品主图等),通过设置 noscript 标签来提供一个不依赖懒加载的备用加载方式。例如:
<noscript>
  <img src="https://example.com/important - image.jpg" alt="Important Image" />
</noscript>
<img v - lazy="imageUrl" alt="Lazy Loaded Image" />

这样,搜索引擎爬虫在不执行 JavaScript 的情况下,也能抓取到图片信息。同时,正常用户访问时,依然可以享受图片懒加载带来的性能优化。

  1. 性能监控与分析
    • 工具使用:可以使用浏览器的开发者工具(如 Chrome DevTools)来监控懒加载的性能。在 Network 面板中,可以观察组件和图片的加载时机、加载时间等。例如,在加载一个包含懒加载组件和图片的页面时,通过 Network 面板可以看到哪些组件和图片是在初始加载时加载的,哪些是在后续触发懒加载时加载的。同时,可以分析加载时间是否过长,如果过长,可以进一步优化懒加载逻辑,比如调整预加载时机、优化网络请求等。
    • 性能指标:关注一些关键性能指标,如首屏加载时间、最大内容绘制时间(Largest Contentful Paint,LCP)等。懒加载的目的是优化这些指标,如果使用懒加载后这些指标没有得到改善甚至变差,就需要检查懒加载的实现是否合理。例如,如果首屏加载时间变长,可能是因为某些原本应该在首屏展示的组件被错误地设置为懒加载,导致首屏渲染时缺少关键内容,从而影响了加载时间。通过不断监控和分析这些性能指标,可以持续优化懒加载策略,提升用户体验。

懒加载在 Vue 项目中是一项非常重要的性能优化技术,通过合理应用组件懒加载和图片懒加载,并注意优化与相关注意事项,可以显著提升 Vue 应用的性能和用户体验,同时也需要兼顾 SEO 等方面的需求,以确保应用在各个方面都能达到较好的效果。在实际项目中,根据项目的具体需求和特点,灵活选择和优化懒加载的实现方式,是前端开发者需要不断探索和实践的重要内容。