骨架屏

154 阅读3分钟

骨架屏——首屏性能优化组件

懒加载优化

即便通过 Webpack 的按需加载、CDN 静态资源缓存 和 代码分割 等技术来减少首屏的代码体积,首屏加载时的白屏时间(也称为首屏等待时间)仍然可能存在,尤其在网络条件较差或页面内容复杂时,常见的解决方案是使用骨架屏技术,数据加载前的占位动画可以表示内容还在加载中。

核心概念和实现思路:

  1. 使用 IntersectionObserver 进行懒加载
    • IntersectionObserver 用来监听目标元素是否进入视区(即视口)。当某个占位元素(如 div 或 section)进入视口时,才异步加载对应的组件。这种方式可以避免首屏加载时不必要的资源占用,提升页面加载速度。
    • 当组件加载完成后,可以根据需求决定是否需要销毁监听器,比如加载完成即销毁,或者离开视区后销毁。
  1. 异步组件加载
    • 在 Vue 中,使用 () => import('component') 来进行异步加载。异步组件的加载是在用户需要时(通常是当组件进入视区时)才会加载,而不是在页面初始加载时。
    • 通过这种懒加载方式,我们可以极大提升首屏加载的性能,因为只有用户能看到的组件会优先加载。
  1. 骨架屏
    • 在真实组件加载前,用骨架屏占位,提供一个与真实组件大小相近的占位元素,让用户感知页面在加载中,避免空白页面的出现。骨架屏可以是简单的 HTML 结构,如 ,并通过 CSS 渲染出类似加载动画的效果。
  1. 内存泄漏防止
    • 在页面或组件销毁时,必须调用 IntersectionObserver.disconnect(),防止继续监听无用的元素,避免内存泄漏。
  • 要点说明:
  • 骨架屏: 用作骨架屏,占位在实际组件加载之前。
  • IntersectionObserver:通过 IntersectionObserver 监听目标元素,当元素进入视区时加载真实组件并销毁观察器。
  • 异步组件加载:this.lazyComponent = () => import('./LazyLoadedComponent.vue'); 在实际需要时才加载组件。

注意点

  • 内存管理:一定要在组件销毁时调用 disconnect() 释放 IntersectionObserver,否则可能导致内存泄漏。

  • 异步组件加载的性能:异步组件加载可以显著减少首屏资源的消耗,但如果过度使用,可能会增加页面的延迟。确保只在必要时使用懒加载。

代码:

 

 ​

 

 export default {

   data() {

     return {

       isVisible: false, // 组件是否可见

       lazyComponent: null // 懒加载的真实组件

    };

  },

   mounted() {

     this.createObserver();

  },

   beforeDestroy() {

     // 销毁时取消监听,防止内存泄漏

     if (this.observer) {

       this.observer.disconnect();

    }

  },

   methods: {

     createObserver() {

       const observerOptions = {

         root: null, // 默认是视口

         threshold: 0.1 // 目标元素至少可见 10% 时触发

      };

 ​

       this.observer = new IntersectionObserver((entries) => {

         entries.forEach((entry) => {

           if (entry.isIntersecting) {

             // 当目标元素进入可视区时,加载真实组件

             this.loadComponent();

             // 加载完成后销毁观察器

             this.observer.disconnect();

          }

        });

      }, observerOptions);

 ​

       // 观察占位符骨架屏

       this.observer.observe(this.$refs.observerTarget);

    },

     loadComponent() {

       // 使用异步组件加载实际组件

       this.lazyComponent = () => import('./LazyLoadedComponent.vue');

       this.isVisible = true; // 组件可见

    }

  }

 };

 

 ​

 

 .skeleton-screen {

   width: 100%;

   height: 200px;

   background-color: #eee; /* 骨架屏的占位效果 */

 }