FORMA

资源优化

图片懒加载、按需引入与 Web Vitals 监控。见 HTML 图片CSS 字体优化

资源优化聚焦于减少网络传输体积、延迟非关键资源加载以及监控真实性能,从而提升页面加载速度和用户体验。

一、图片懒加载:配合 IntersectionObserver 的 Vue 指令

图片懒加载是一种优化首屏加载的常用手段:只有当图片进入视口(或视口附近)时才加载真实图片,避免一次性加载大量不可见图。

1. 原生实现:IntersectionObserver

IntersectionObserver 可以高效监听元素与视口的交叉状态,相比 scroll 事件 + getBoundingClientRect,它由浏览器底层异步处理,性能更优。

基础用法

js
const observer = new IntersectionObserver(
  (entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        const img = entry.target;
        const src = img.dataset.src;
        if (src) {
          img.src = src;
          img.removeAttribute("data-src");
        }
        observer.unobserve(img);
      }
    });
  },
  { rootMargin: "0px 0px 100px 0px" },
); // 提前 100px 开始加载
document.querySelectorAll("img[data-src]").forEach((img) => observer.observe(img));

2. 封装为 Vue 指令(v-lazy

为了方便复用,可以封装一个自定义指令,支持动态绑定、响应式更新。

js
// directives/lazy.js
export default {
  mounted(el, binding) {
    // 用 data-src 存储真实图片地址
    el.dataset.src = binding.value;
    const observer = new IntersectionObserver(
      (entries) => {
        if (entries[0].isIntersecting) {
          el.src = el.dataset.src;
          delete el.dataset.src;
          observer.unobserve(el);
        }
      },
      { rootMargin: "0px 0px 100px 0px" },
    );
    observer.observe(el);
    // 存储 observer 以便 unmounted 时断开
    el._lazyObserver = observer;
  },
  unmounted(el) {
    if (el._lazyObserver) {
      el._lazyObserver.disconnect();
      delete el._lazyObserver;
    }
  },
};

在组件中使用:

vue
<template>
  <img v-lazy="imageUrl" alt="懒加载图片" />
</template>

3. 结合 Vue 生态的现成方案

  • vue-lazyload:Vue 2 经典,Vue 3 有 vue-lazyload-next
  • v-lazy-image 等轻量库。

对于背景图片懒加载,可设置 data-bg,在 IntersectionObserver 中修改 el.style.backgroundImage

二、第三方库按需引入与 Tree Shaking

使用第三方库时,若全量引入会显著增加打包体积。按需引入 + Tree Shaking 可以只打包被使用的代码。

1. 使用按需导入的库(如 lodash-es)

  • 推荐使用 lodash-es(ES 模块版本),而非 lodash(CommonJS)。因为 lodash-es 支持 Tree Shaking。
js
// ❌ 全量引入 lodash
import _ from 'lodash';
_.debounce(...);

// ✅ 按需引入
import debounce from 'lodash-es/debounce';
// 或
import { debounce } from 'lodash-es';

确保构建工具(Webpack、Vite)在生产模式开启 sideEffects 优化。Vite 默认支持,Webpack 需要 mode: 'production' 或显式配置 optimization.usedExports

2. UI 组件库按需引入( element-plus 为例)

大多数现代 UI 库都提供按需引入方式。例如 element-plus 推荐使用 unplugin-auto-importunplugin-vue-components 插件自动按需引入。

手动按需引入

js
import { ElButton, ElMessage } from "element-plus";
// 单独引入样式(组件库通常提供按需样式的插件)
import "element-plus/es/components/button/style/css";

使用插件自动按需(推荐)

js
// vite.config.js
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";

export default {
  plugins: [
    AutoImport({ resolvers: [ElementPlusResolver()] }),
    Components({ resolvers: [ElementPlusResolver()] }),
  ],
};

这样,模板中使用的 <el-button> 会自动引入对应组件和样式,且支持 Tree Shaking。

3. 确保库支持 Tree Shaking 的条件

  • 库使用 ES 模块(ESM)格式,且 package.json"sideEffects": false 或明确声明。
  • 避免只在 index.js 中集中导出(二级导入通常可避免全量加载)。
  • 使用构建工具的 optimization 选项(Webpack)或 Vite 默认配置。

4. 工具排查未使用的依赖

  • webpack-bundle-analyzerrollup-plugin-visualizervite-bundle-visualizer 生成体积报告,找出全量引入的库。

三、首屏性能监控:Lighthouse & Web Vitals

性能监控是优化的前提,通过定量指标了解真实用户体验。

1. Lighthouse(实验室工具)

Lighthouse 是 Google 出品的高仿真性能审计工具,可在 Chrome DevTools、PageSpeed Insights 或 CLI 中使用。它给出综合评分(性能、可访问性、SEO 等)并提供具体优化建议。

核心关注指标(与 Web Vitals 重叠):

  • FCP(First Contentful Paint):首次内容绘制时间。
  • LCP(Largest Contentful Paint):最大内容绘制,衡量加载性能。
  • TBT(Total Blocking Time):总阻塞时间,交互准备度。
  • CLS(Cumulative Layout Shift):累计布局偏移,视觉稳定性。
  • Speed Index:速度指数。

分析流程

  1. 运行 Lighthouse(DevTools → Lighthouse 面板,选择 Mobile 或 Desktop)。
  2. 查看性能评分和 “Opportunities” 列表(例如 “减少未使用的 JavaScript”、 “适当调整图片大小”)。
  3. 按建议优化后重新测试。

2. Web Vitals(真实用户监控)

Web Vitals 是一组由 Google 定义的、衡量真实用户体验的核心指标,通常通过 现场数据(CrUX 报告)或 实验室数据(Lighthouse)获取。

指标含义良好阈值 (75分位)
LCP最大内容元素渲染完成时间≤ 2.5秒
INP (取代 FID)交互延迟(Next Paint),衡量响应性≤ 200毫秒
CLS页面布局意外偏移程度≤ 0.1

监控方式

  • Chrome 用户体验报告 (CrUX):基于真实 Chrome 用户的匿名数据,可通过 PageSpeed Insights 查看域名总体表现。
  • JavaScript API:使用 web-vitals 库收集并上报。
js
import { onLCP, onINP, onCLS } from "web-vitals";
onLCP(console.log);
onINP(console.log);
onCLS(console.log);

3. 基于指标的优化策略

差指标常见原因优化策略
LCP 慢主资源(hero image)加载慢,首屏阻塞优化图片(WebP、响应式)、预加载 LCP 元素、CDN、服务器端渲染(SSR)
INP 差长任务阻塞主线程、过多输入延迟拆分长任务(使用 setTimeoutscheduler.yield)、避免繁重的 JS 执行、使用 Web Worker
CLS 高图片/iframe 无尺寸占位、动态注入内容为所有媒体元素设置 width/height 或 CSS aspect-ratio;预留广告位;字体使用 font-display: optional 减少 FOIT
TBT 高大量未使用/未拆分的 JS代码分割、懒加载非关键脚本、减少 polyfill

4. 性能预算

设定性能预算(比如 LCP < 2s, JS 总体积 < 200KB),并在 CI 中集成 Lighthouse CI 或 lighthouse-bot,监控每次 PR 是否突破预算。

总结

资源优化方面核心技术收益
图片懒加载IntersectionObserver + Vue 指令封装减少非可视区图片加载,提升首屏速度
按需引入与 Tree ShakingESM 模块、自动按需插件、sideEffects 配置大幅减小打包体积,仅包含实际使用的代码
首屏性能监控Lighthouse(实验室)+ Web Vitals(真实)量化性能瓶颈,指导优化方向,跟踪迭代效果

通过以上资源优化手段,可以系统性地降低加载开销,并从数据层面持续提升用户体验。

参考文献

以下链接在编写时均可正常访问:

资料说明
MDN:Intersection Observer懒加载基础
MDN:loading=lazy原生图片懒加载
web.dev:LCP最大内容绘制(英文)
web.dev:CLS布局偏移(英文)

Series

performance

1 / 3