npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

vane-lazy-image

v1.0.20

Published

高性能的 React 图片懒加载组件,支持 LQIP、Web Worker、虚拟滚动等功能

Downloads

93

Readme

🖼️ Vane Lazy Image

一个功能强大、高度可扩展的 React 图片懒加载组件库

NPM Version License TypeScript React Performance

在线演示 | 快速开始 | 插件列表 | API 文档


🚀 v1.0.20 重大更新

性能优化革命 - 减少 99% 资源消耗

通过 GlobalContext 全局单例 + ObserverPool 共享池双重优化,实现前所未有的性能提升!

核心优化

| 优化项 | 优化前 | 优化后 | 提升幅度 | |--------|--------|--------|----------| | 网络检测 | 每个组件独立检测 | 全局单例缓存 | ⬇️ 99% | | 设备检测 | 每个组件独立检测 | 全局单例缓存 | ⬇️ 99% | | Observer 实例 | 100 张图片 = 100 个 Observer | 100 张图片 = 1 个 Observer | ⬇️ 99% | | 事件监听器 | 每个组件独立监听 | 全局共享监听 | ⬇️ 95% | | 性能检测次数 | 100 张图片 = 200 次检测 | 100 张图片 = 2 次检测 | ⬇️ 99% |

实际效果

// 100 张图片场景对比
优化前:200 次网络/设备检测 + 100 个 Observer 实例
优化后:2 次网络/设备检测 + 1 个 Observer 实例

内存占用:⬇️ 99%
CPU 占用:⬇️ 95%
初始化时间:⬇️ 98%

新增功能

  • 🌐 GlobalContext - 全局单例上下文管理
  • 👁️ ObserverPool - IntersectionObserver 共享池
  • 性能优化综合演示 - 实时查看优化效果
  • 🔄 插件热更新 - 运行时动态注册/卸载插件
  • 🔗 依赖解析器 - 自动解析插件依赖关系
  • 🛡️ 插件沙箱 - 隔离插件执行环境

💡 查看演示:访问 在线演示 查看详细的性能对比


✨ 核心特性

🔌 插件化架构

  • 基于事件总线的插件系统,支持灵活组合
  • 71 个内置插件,覆盖各种使用场景
  • 90+ 在线演示页面,提供完整的使用示例
  • 易于扩展,支持自定义插件开发
  • 插件热更新、依赖解析、沙箱隔离

🎨 丰富的视觉效果

  • 水印、模糊占位(BlurUp)、渐变过渡
  • 滤镜、边框发光、视差滚动
  • 骨架屏、进度条、信息叠层、角标
  • 支持自定义 CSS 效果组合

性能优化

  • GlobalContext 全局单例,减少 99% 检测次数
  • ObserverPool 共享池,减少 99% 内存占用
  • 优先级加载控制
  • 预连接(Preconnect)降低网络延迟
  • 并发控制,避免资源竞争
  • 内存缓存 + IndexedDB 持久化缓存
  • 滚动空闲检测,优化用户体验

🛡️ 错误处理

  • 智能重试机制(指数退避)
  • CDN 回退策略
  • 降级加载(Fallback Image)
  • 离线缓存支持
  • 错误追踪与上报
  • 插件沙箱隔离错误

可访问性与 SEO

  • ARIA 属性自动注入
  • Alt 文本智能填充
  • 结构化数据支持
  • 搜索引擎优化
  • 响应式图片(srcset/sizes)
  • 符合 WCAG 2.1 标准

📊 监控与分析

  • 性能指标采集
  • 网络分析与上报
  • 用户行为追踪
  • 加载时序统计
  • 自定义事件日志
  • 完整的性能监控系统

📦 安装

NPM / Yarn / PNPM

# npm
npm install vane-lazy-image

# yarn
yarn add vane-lazy-image

# pnpm
pnpm add vane-lazy-image

本地开发

如果您想本地运行演示站点或进行二次开发:

# 克隆仓库
git clone https://github.com/frankvane/vane-lazy-image.git

# 进入项目目录
cd vane-lazy-image

# 安装依赖
npm install

# 启动开发服务器
npm run dev

# 构建生产版本(库模式)
npm run build

# 构建演示站点
npm run build:demo

# 预览构建产物
npm run preview

📊 包大小与优化

构建产物大小

| 模块 | 原始大小 | Gzip 后 | 说明 | | -------- | -------- | ------- | ---------------------------------- | | index.js (主入口) | 29.06 KB | 9.73 KB | 包含核心组件和常用功能 | | core.js | 0.47 KB | 0.30 KB | 仅核心组件 LazyLoadImageCore | | plugins.js | 0.30 KB | 0.16 KB | 插件系统(PluginManager、withPlugins) | | advanced.js | 7.55 KB | 2.77 KB | 高级功能(Sandbox、DependencyResolver) | | monitoring.js | 6.08 KB | 2.25 KB | 性能监控系统 | | custom-plugins.js | 2.45 KB | 0.93 KB | 所有自定义插件索引 |

💡 提示:使用按需导入可以大幅减小最终打包体积,推荐生产环境使用。

Tree-Shaking 支持

本库完全支持 Tree-Shaking,未使用的插件不会被打包到最终产物中。

为什么支持 Tree-Shaking?

  1. ESM 模块格式:采用 ES Module 格式发布,便于静态分析
  2. 无副作用标记:在 package.json 中设置 "sideEffects": false
  3. 命名导出:所有功能都使用命名导出,而非默认导出
  4. 独立模块:每个插件都是独立的模块,可单独引入
// package.json
{
  "sideEffects": false,
  "module": "./dist/index.js",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js"
    },
    "./core": {
      "types": "./dist/entries/core/index.d.ts",
      "import": "./dist/core.js"
    },
    "./plugins": {
      "types": "./dist/entries/plugins/index.d.ts",
      "import": "./dist/plugins.js"
    }
  }
}

✅ 支持 Tree-Shaking 的导入方式

// 推荐:按需导入(支持 Tree-Shaking)
import {
  LazyLoadImageCore,
  withPlugins,
  createWatermarkPlugin,
  createFadeInPlugin,
} from "vane-lazy-image";

// 只会打包使用到的插件
// 最终大小:~13 KB (核心 + 系统 + 2个插件)

⚠️ 不推荐的导入方式

// ❌ 不推荐:导入所有插件
import * as LazyImage from "vane-lazy-image";

// 会打包所有 59 个插件
// 最终大小:~280 KB

按需导入示例

方式一:精确导入(最小体积)

// 仅导入需要的功能
import { LazyLoadImageCore } from "vane-lazy-image/core";
import { withPlugins } from "vane-lazy-image/plugins";
import { createWatermarkPlugin } from "vane-lazy-image/custom-plugins";
import { createFadeInPlugin } from "vane-lazy-image/custom-plugins";

// 打包大小:~13 KB (最小)

方式二:分类导入(推荐)

// 从主入口导入核心和常用插件
import {
  LazyLoadImageCore,
  withPlugins,
  createWatermarkPlugin,
  createFadeInPlugin,
  createRetryOnErrorPlugin,
} from "vane-lazy-image";

// 打包大小:~16 KB (核心 + 3个插件)

方式三:分组导入

// 视觉效果插件组
import {
  createWatermarkPlugin,
  createFadeInPlugin,
  createBlurUpPlugin,
  createSkeletonPlugin,
} from "vane-lazy-image";

// 性能优化插件组
import {
  createPreconnectPlugin,
  createCacheMemoryPlugin,
  createConcurrencyControlPlugin,
} from "vane-lazy-image";

// 打包大小:~30 KB (核心 + 7个插件)

不同场景的包大小对比

| 使用场景 | 导入插件数 | 预估大小(Gzip) | | ---------------- | ---------- | ---------------- | | 最小化(仅核心) | 0 | ~3 KB | | 基础使用 | 2-3 个 | ~10-15 KB | | 常规项目 | 5-8 个 | ~18-28 KB | | 功能丰富 | 10-15 个 | ~35-50 KB | | 完整功能 | 59 个 | ~85 KB |


🚀 快速开始

基础使用

最简单的使用方式,不带任何插件:

import { LazyLoadImageCore } from "vane-lazy-image";

function App() {
  return (
    <div style={{ width: 480, height: 300 }}>
      <LazyLoadImageCore
        src="https://picsum.photos/800/600"
        alt="示例图片"
        loading="lazy"
        containerStyle={{ width: "100%", height: "100%" }}
        imageStyle={{ width: "100%", height: "100%", objectFit: "cover" }}
      />
    </div>
  );
}

使用插件

通过 withPlugins 高阶组件组合多个插件:

import {
  LazyLoadImageCore,
  withPlugins,
  createWatermarkPlugin,
  createFadeInPlugin,
  createRetryOnErrorPlugin,
} from "vane-lazy-image";

// 组合插件
const LazyImage = withPlugins(LazyLoadImageCore, [
  createWatermarkPlugin({
    text: "VANE",
    position: "bottom-right",
    opacity: 0.6,
  }),
  createFadeInPlugin({
    durationMs: 600,
  }),
  createRetryOnErrorPlugin({
    maxRetries: 3,
    retryDelay: 1000,
  }),
]);

function App() {
  return (
    <div style={{ width: 480, height: 300 }}>
      <LazyImage
        src="https://picsum.photos/800/600"
        alt="带插件的图片"
        loading="lazy"
        containerStyle={{ width: "100%", height: "100%" }}
        imageStyle={{ width: "100%", height: "100%", objectFit: "cover" }}
      />
    </div>
  );
}

组合示例:性能优化

import {
  LazyLoadImageCore,
  withPlugins,
  createPreconnectPlugin,
  createPriorityLoadingPlugin,
  createImageOptimizationPlugin,
  createCacheMemoryPlugin,
  createConcurrencyControlPlugin,
} from "vane-lazy-image";

const LazyImage = withPlugins(LazyLoadImageCore, [
  createPreconnectPlugin({
    domains: ["https://images.example.com"],
  }),
  createPriorityLoadingPlugin({
    loading: "lazy",
    rootMargin: "200px",
  }),
  createImageOptimizationPlugin({
    widthParam: "w",
    qualityParam: "q",
    defaultQuality: 80,
  }),
  createCacheMemoryPlugin({
    maxSize: 50,
  }),
  createConcurrencyControlPlugin({
    maxConcurrent: 4,
  }),
]);

export default function PerformanceDemo() {
  const images = [
    "https://images.example.com/photo1.jpg",
    "https://images.example.com/photo2.jpg",
    "https://images.example.com/photo3.jpg",
  ];

  return (
    <div style={{ display: "grid", gap: 16 }}>
      {images.map((src, i) => (
        <LazyImage
          key={i}
          src={src}
          alt={`图片 ${i + 1}`}
          loading="lazy"
          containerStyle={{ width: 320, height: 200 }}
          imageStyle={{ width: "100%", height: "100%", objectFit: "cover" }}
        />
      ))}
    </div>
  );
}

📚 插件列表

本项目提供 71 个开箱即用的插件,按功能分类如下:

🎨 视觉与效果(14 个)

| 插件 | 说明 | | ----------------------------- | -------------------------------- | | createWatermarkPlugin | 为图片叠加水印文本或标识 | | createBadgePlugin | 添加角标或状态标记 | | createProgressOverlayPlugin | 加载进度条与百分比文本覆盖层 | | createSkeletonPlugin | 骨架屏遮罩,支持 shimmer 动画 | | createOverlayInfoPlugin | 信息蒙层,支持顶部/底部/居中显示 | | createBlurUpPlugin | 从模糊到清晰的渐进过渡效果 | | createFadeInPlugin | 图片淡入动画 | | createDominantColorPlugin | 提取主色用于背景占位 | | createGalleryPlugin | 大图/灯箱查看能力 | | createFilterPlugin | CSS 滤镜,支持悬停交互 | | createCaptionPlugin | 图片说明文字叠层 | | createBorderGlowPlugin | 边框发光视觉效果 | | createParallaxPlugin | 视差滚动效果 | | createColorExtractionPlugin | 颜色提取用于背景/主题 |

⚡ 性能与网络(15 个)

| 插件 | 说明 | | ---------------------------------- | ------------------------------- | | createPreconnectPlugin | 预连接目标域名,降低延迟 | | createPriorityLoadingPlugin | 控制加载优先级策略 | | createCachePrewarmPlugin | 缓存预热与链接提前建立 | | createCacheMemoryPlugin | 内存缓存策略(LRU) | | createCacheIDBPlugin | IndexedDB 持久缓存 | | createConcurrencyControlPlugin | 限制并发加载数量 | | createScrollIdlePlugin | 滚动空闲后再加载 | | createNetworkAnalyticsPlugin | 网络事件与性能数据上报 | | createPredictiveLoadingPlugin | 预测性预加载下一个资源 | | createDataSaverPlugin | 省流模式降级策略 | | createImageOptimizationPlugin | 图片参数优化(尺寸、质量) | | createHoverPrefetchPlugin | 悬停预取资源 | | createDecodeAfterIdlePlugin | 空闲后再解码 | | GlobalContext 🆕 | 全局单例上下文管理 | | ObserverPool 🆕 | IntersectionObserver 共享池 |

🛡️ 稳健性与错误处理(11 个)

| 插件 | 说明 | | --------------------------------- | -------------------------- | | createErrorBadgePlugin | 失败状态显示角标 | | createErrorOverlayPlugin | 加载失败覆盖层提示 | | createFallbackImagePlugin | 失败回退到备用图片 | | createRetryOnErrorPlugin | 错误重试与退避策略 | | createErrorTrackingPlugin | 错误追踪与上报 | | createOfflinePlugin | 离线占位与状态提示 | | createMemoryPressureAbortPlugin | 内存压力触发取消请求 | | createAntiHotlinkPlugin | 防盗链策略 | | createCDNFallbackPlugin | CDN 失败回退主源 | | createAuthPlugin | 鉴权/携带 token 的资源加载 | | createRedactionPlugin | 敏感信息遮蔽/打码处理 |

👆 视口与交互(8 个)

| 插件 | 说明 | | ------------------------------ | ------------------------ | | createViewportAwarePlugin | 细粒度的视口状态管理 | | createViewportDebouncePlugin | 视口变化防抖处理 | | createViewportDwellPlugin | 基于驻留时长的加载策略 | | createUserBehaviorPlugin | 用户行为统计 | | createHoverZoomPlugin | 悬停放大交互 | | createComparisonPlugin | 前后对比滑块 | | createCropPlugin | 裁剪与展示区域控制 | | createHoverPrefetchPlugin | 悬停预取资源 |

♿ 可访问性与 SEO(6 个)

| 插件 | 说明 | | ------------------------------- | ---------------------------- | | createA11yPlugin | 可访问性增强(ARIA、焦点) | | createAltTextPlugin | Alt 文本智能填充 | | createSEOPlugin | 搜索引擎优化 | | createAspectRatioSpacerPlugin | 按长宽比占位减少布局偏移 | | createExifOrientationPlugin | EXIF 方向矫正 | | createResponsivePlugin | 响应式 srcset/sizes 管理 |

🔧 其他(8 个)

| 插件 | 说明 | | -------------------------------- | ------------------------- | | createEventLoggerPlugin | 事件日志打印与上报 | | createPerformanceMonitorPlugin | 性能指标采集 | | createLQIPPlugin | 低质量图像占位(LQIP) | | createSvgPlaceholderPlugin | SVG 占位图渲染 | | createWebPPlugin | WebP 优先加载与回退 | | createAdaptiveQualityPlugin | 基于网络/设备的自适应质量 | | createBatteryAwarePlugin | 电量/省电模式适配 | | createTransitionPlugin | 统一管理加载过渡效果 |

🛒 电商场景(5 个)

| 插件 | 说明 | | -------------------------------- | ----------------------------- | | createPriceTagPlugin | 价格标签显示 | | createPromoBadgePlugin | 促销角标(NEW/HOT/SALE等) | | createInventoryStatusPlugin | 库存状态提示 | | createColorSwatchPlugin | 颜色提取与切换 | | createSocialSharePlugin | 社交分享按钮 |

🔨 实用工具(3 个)

| 插件 | 说明 | | -------------------------------- | ----------------------------- | | createVideoPosterPlugin | 视频封面与播放控制 | | createLocalizationPlugin | 多语言图片适配 | | createDownloadButtonPlugin | 图片下载按钮 |

🎭 视觉效果与交互(5 个)

| 插件 | 说明 | | -------------------------------- | ----------------------------- | | createRevealAnimationPlugin | 图片揭示动画(淡入、缩放、旋转等) | | createGlitchEffectPlugin | 故障艺术效果(RGB分离、扫描线等) | | createMorphPlugin | 形变动画(弹性、液态、扭曲等) | | createAnimatedCursorPlugin | 自定义光标动画与交互效果 | | createDepthMapPlugin | 3D 视差与倾斜效果 |

🚀 高级功能(Advanced & Monitoring)

| 模块 | 说明 | | ----------------------------- | ------------------------- | | Plugin Sandbox 🆕 | 插件沙箱机制,隔离执行环境 | | Performance Monitoring 🆕 | 完整的性能监控系统 | | Plugin Hot Reload 🆕 | 运行时插件热更新 | | Dependency Resolver 🆕 | 自动依赖解析和版本管理 | | Plugin Manager | 插件生命周期管理 | | Plugin Bus | 插件间通信总线 | | FetchLoaderPlugin | 自定义 Fetch 加载器 |

💡 提示:所有插件都可以通过 vane-lazy-image 包导入。高级功能通过 vane-lazy-image/advancedvane-lazy-image/monitoring 模块导入。详细配置请参考 API 文档 或查看 在线演示


🚀 高级功能 API

Plugin Sandbox - 插件沙箱机制

提供隔离的插件执行环境,防止错误插件影响整个应用。

导入方式

import { createPluginSandbox, wrapPluginHook } from "vane-lazy-image/advanced";

主要功能

  • ✅ 错误隔离:捕获插件内的异常
  • ✅ 超时控制:防止死循环和长时间执行
  • ✅ 资源清理:自动清理监听器和资源
  • ✅ 命名空间:隔离 sharedData 访问

使用示例

import { wrapPluginHook, SandboxConfig } from "vane-lazy-image/advanced";

// 配置沙箱
const config: SandboxConfig = {
  pluginName: "MyPlugin",
  enabled: true,
  hookTimeout: 5000,  // 5秒超时
  autoCleanup: true,  // 自动清理
  debug: true,        // 调试模式
};

// 包装插件钩子
const safeHook = wrapPluginHook(unsafeHook, config);

// 或创建沙箱化的上下文
const sandboxedContext = createPluginSandbox(context, config);

应用场景

  • 第三方插件集成
  • 开发环境调试
  • 生产环境错误隔离

Performance Monitoring - 性能监控系统

完整的性能追踪和分析系统,提供实时性能报告。

导入方式

import {
  createPerformanceMonitor,
  getGlobalMonitorManager
} from "vane-lazy-image/monitoring";

主要功能

  • ✅ 实时指标收集(TTFB、下载、解码)
  • ✅ 自动性能报告生成
  • ✅ 全局监控管理器
  • ✅ 性能阈值警告
  • ✅ 详细性能分析

使用示例

import { createPerformanceMonitor, getGlobalMonitorManager }
  from "vane-lazy-image/monitoring";

// 创建监控器
const monitor = createPerformanceMonitor({
  enableAutoReport: true,
  reportInterval: 5000,
  thresholds: {
    loadTime: 3000,
    ttfb: 500,
    decodeTime: 100,
  },
  onReport: (report) => {
    console.log("性能报告:", report);
  },
});

// 启动监控
monitor.start();

// 获取全局统计
const manager = getGlobalMonitorManager();
const summary = manager.generateSummaryReport();

// 停止监控
monitor.stop();

报告数据结构

interface PerformanceReport {
  url: string;
  timestamp: number;
  metrics: {
    totalLoadTime: number;
    ttfb?: number;
    downloadTime?: number;
    decodeTime?: number;
    fileSize?: number;
  };
}

Plugin Hot Reload - 插件热更新

运行时动态注册、卸载和替换插件,无需重启应用。

主要功能

  • ✅ 运行时注册新插件
  • ✅ 动态卸载已有插件
  • ✅ 热替换插件配置
  • ✅ 实时生效

使用示例

import { createPluginManager } from "vane-lazy-image/plugins";

const manager = createPluginManager();

// 注册插件
const fadeIn = createFadeInPlugin({ durationMs: 500 });
const success = manager.register(fadeIn);  // 返回 true/false

// 运行时添加新插件(热注册)
const watermark = createWatermarkPlugin({ text: "New" });
manager.register(watermark);

// 卸载插件(热卸载)
manager.unregister("watermark");

// 替换插件(热替换)
manager.unregister("fadeIn");
const newFadeIn = createFadeInPlugin({ durationMs: 1500 });
manager.register(newFadeIn);

// 获取当前激活的插件
const activePlugins = manager.getActivePlugins();

// 使用激活的插件
const Image = withPlugins(LazyLoadImageCore, activePlugins);

应用场景

  • A/B 测试不同插件配置
  • 动态功能开关
  • 插件市场/商店
  • 用户自定义配置

Dependency Resolver - 依赖解析器

自动解析插件依赖关系,确定正确的加载顺序。

主要功能

  • ✅ 自动拓扑排序(Topological Sort)
  • ✅ 循环依赖检测
  • ✅ 版本兼容性检查(Semver)
  • ✅ 缺失依赖警告
  • ✅ 冲突检测

使用示例

import { DependencyResolver } from "vane-lazy-image/advanced";

const resolver = new DependencyResolver();

// 添加插件(带依赖信息)
resolver.addPlugin("PluginA", [], ["PluginB"]);  // A 依赖 B
resolver.addPlugin("PluginB");
resolver.addPlugin("PluginC", ["PluginA"]);      // C 依赖 A

// 检测循环依赖
const cycles = resolver.detectCycles();
if (cycles.length > 0) {
  console.error("检测到循环依赖:", cycles);
}

// 获取拓扑排序
const order = resolver.getTopologicalOrder();
// order: ["PluginB", "PluginA", "PluginC"] - 自动排序!

// 检测冲突
const conflicts = resolver.checkConflicts();
if (conflicts.length > 0) {
  console.warn("检测到冲突:", conflicts);
}

应用场景

  • 插件市场/生态系统
  • 复杂插件链管理
  • 团队协作开发
  • 插件版本管理

📂 项目结构

vane-lazy-image/
├── src/
│   ├── components/
│   │   └── LazyLoadImagePlugin/
│   │       ├── core/
│   │       │   ├── LazyLoadImageCore.tsx    # 核心组件
│   │       │   └── ObserverPool.ts          # Observer 共享池 🆕
│   │       ├── plugins/
│   │       │   ├── types.ts                 # 插件类型定义
│   │       │   ├── PluginBus.ts             # 事件总线
│   │       │   ├── PluginManager.ts         # 插件管理器
│   │       │   ├── PluginSandbox.ts         # 插件沙箱 🆕
│   │       │   ├── withPlugins.tsx          # HOC 组合方法
│   │       │   ├── FetchLoaderPlugin.ts     # Fetch 加载器
│   │       │   └── index.ts                 # 插件系统导出
│   │       ├── custom-plugins/              # 59 个自定义插件
│   │       │   ├── WatermarkPlugin/
│   │       │   ├── FadeInPlugin/
│   │       │   ├── RetryOnErrorPlugin/
│   │       │   └── ... (56 more)
│   │       ├── utils/
│   │       │   ├── GlobalContext.ts         # 全局上下文 🆕
│   │       │   ├── DependencyResolver.ts    # 依赖解析器 🆕
│   │       │   ├── PerformanceMonitor.ts    # 性能监控 🆕
│   │       │   ├── LRUCache.ts              # LRU 缓存
│   │       │   └── versionCompare.ts        # 版本比较
│   │       ├── entries/                     # 多入口点
│   │       │   ├── core/index.ts            # 核心入口
│   │       │   ├── plugins/index.ts         # 插件系统入口
│   │       │   ├── advanced/index.ts        # 高级功能入口
│   │       │   └── monitoring/index.ts      # 监控入口
│   │       ├── constants.ts                 # 常量定义
│   │       └── index.ts                     # 主入口
│   ├── pages/
│   │   └── LazyLoadImagePlugin/
│   │       ├── _layout/
│   │       │   └── DemoPage.tsx             # 演示页面布局
│   │       ├── Home.tsx                     # 首页
│   │       ├── WatermarkDemo.tsx            # 各插件演示页面
│   │       ├── PluginHotReloadDemo.tsx      # 热更新演示 🆕
│   │       ├── DependencyResolverDemo.tsx   # 依赖解析演示 🆕
│   │       ├── PluginSandboxDemo.tsx        # 沙箱演示 🆕
│   │       ├── GlobalContextDemo.tsx        # 全局上下文演示 🆕
│   │       ├── ObserverPoolDemo.tsx         # Observer池演示 🆕
│   │       └── ... (80+ 演示文件)
│   ├── App.tsx                              # 应用入口
│   ├── App.css                              # 全局样式
│   └── main.tsx                             # React 入口
├── dist/                                    # 构建产物
│   ├── index.js                             # 主入口 (29.06 KB)
│   ├── core.js                              # 核心入口 (0.47 KB)
│   ├── plugins.js                           # 插件系统 (0.30 KB)
│   ├── advanced.js                          # 高级功能 (7.55 KB)
│   ├── monitoring.js                        # 监控系统 (6.08 KB)
│   ├── custom-plugins.js                    # 插件索引 (2.45 KB)
│   └── *.d.ts                               # TypeScript 类型定义
├── public/                                  # 静态资源
├── vite.config.ts                           # Vite 配置
├── tsconfig.json                            # TypeScript 配置
├── package.json                             # 项目配置
└── README.md                                # 项目文档

🎯 API 文档

核心组件:LazyLoadImageCore

Props

| 属性 | 类型 | 默认值 | 说明 | | -------------------- | --------------------- | -------- | ------------ | | src | string | 必填 | 图片 URL | | alt | string | "" | 替代文本 | | loading | "lazy" \| "eager" | "lazy" | 加载策略 | | rootMargin | string | "0px" | 视口边距 | | threshold | number \| number[] | 0.01 | 可见度阈值 | | containerStyle | React.CSSProperties | {} | 容器样式 | | imageStyle | React.CSSProperties | {} | 图片样式 | | containerClassName | string | "" | 容器类名 | | imageClassName | string | "" | 图片类名 | | onLoad | () => void | - | 加载完成回调 | | onError | () => void | - | 加载失败回调 |

HOC:withPlugins

function withPlugins<P extends CoreImageProps>(
  Component: React.ComponentType<P>,
  plugins: LazyImagePlugin[]
): React.FC<P>;

参数

  • Component:核心组件(通常是 LazyLoadImageCore
  • plugins:插件数组

返回值

增强后的 React 组件

插件类型定义

核心插件接口

interface LazyImagePlugin {
  name: string;
  version?: string;
  hooks: PluginHooks;
  config?: Record<string, any>;
  init?: () => void | Promise<void>;
  destroy?: () => void | Promise<void>;
}

插件上下文

interface PluginContext {
  // 基础属性
  src: string;
  imageState: UseImageStateReturnLike;
  containerRef: React.RefObject<HTMLElement | null>;
  imageRef?: React.RefObject<HTMLImageElement | null>;
  isIntersecting: boolean;
  props: LazyLoadImageCoreProps;
  bus?: PluginBus;

  // 扩展上下文
  networkInfo?: NetworkInfo;
  deviceInfo?: DeviceInfo;
  dimensions?: {
    width: number;
    height: number;
    naturalWidth?: number;
    naturalHeight?: number;
  };
  performanceData?: {
    loadStartTime: number;
    loadEndTime?: number;
    duration?: number;
    size?: number;
  };
  sharedData?: Map<string, any>;
}

interface UseImageStateReturnLike {
  isIdle: boolean;
  isLoading: boolean;
  isLoaded: boolean;
  isError: boolean;
}

插件钩子

interface PluginHooks {
  // 生命周期钩子
  onMount?: (context: PluginContext) => void | (() => void);
  onUnmount?: (context: PluginContext) => void;

  // 加载流程钩子
  onBeforeLoad?: (context: PluginContext) => boolean | Promise<boolean>;
  onLoad?: (
    context: PluginContext
  ) => string | Promise<string | undefined> | undefined;
  onLoadSuccess?: (
    context: PluginContext,
    displaySrc?: string
  ) => void | Promise<void>;
  onLoadError?: (
    context: PluginContext,
    error: Error
  ) => boolean | Promise<boolean>;

  // 视口钩子
  onEnterViewport?: (context: PluginContext) => void;
  onLeaveViewport?: (context: PluginContext) => void;
  onVisibilityChange?: (context: PluginContext, isVisible: boolean) => void;

  // 进度与重试
  onProgress?: (context: PluginContext, progress: ProgressInfo) => void;
  onRetry?: (
    context: PluginContext,
    retryCount: number,
    maxRetries: number
  ) => void;

  // 状态变化钩子
  onSrcChange?: (
    context: PluginContext,
    oldSrc: string,
    newSrc: string
  ) => void;
  onNetworkChange?: (context: PluginContext, networkInfo: NetworkInfo) => void;
  onResize?: (context: PluginContext, dimensions: Dimensions) => void;

  // 交互钩子
  onInteraction?: (
    context: PluginContext,
    interactionType: InteractionType
  ) => void;

  // 其他钩子
  onAbort?: (context: PluginContext) => void;
  onDecode?: (context: PluginContext) => void;
  onPaint?: (context: PluginContext) => void;

  // 渲染钩子
  render?: (context: PluginContext) => React.ReactNode;
  renderOverlay?: (context: PluginContext) => React.ReactNode;

  // Props 转换
  transformProps?: (props: LazyLoadImageCoreProps) => LazyLoadImageCoreProps;
}

辅助类型

// 进度信息
interface ProgressInfo {
  loaded: number;
  total: number;
  percent: number; // 0~100
  indeterminate?: boolean;
}

// 网络信息
interface NetworkInfo {
  effectiveType: "4g" | "3g" | "2g" | "slow-2g";
  downlink: number; // Mbps
  rtt: number; // ms
  saveData: boolean;
}

// 设备信息
interface DeviceInfo {
  type: "mobile" | "tablet" | "desktop";
  os: string;
  browser: string;
  devicePixelRatio: number;
  viewportWidth: number;
  viewportHeight: number;
}

// 尺寸信息
interface Dimensions {
  width: number;
  height: number;
}

// 交互类型
type InteractionType = "click" | "hover" | "focus" | "touch";

插件通信总线

interface PluginBus {
  emit: (event: string, data: any) => void;
  on: (event: string, handler: (data: any) => void) => () => void;
  getData: (key: string) => any;
  setData: (key: string, value: any) => void;
}

插件管理器

interface PluginManager {
  register: (plugin: LazyImagePlugin) => boolean;
  unregister: (pluginName: string) => boolean;
  getPlugin: (pluginName: string) => LazyImagePlugin | undefined;
  getActivePlugins: () => LazyImagePlugin[];
  getAllPlugins: () => LazyImagePlugin[];
  executeHook: <K extends keyof PluginHooks>(
    hookName: K,
    context: PluginContext,
    ...args: any[]
  ) => Promise<any>;
}

🌟 性能优化 API

GlobalContext - 全局单例上下文

GlobalContext 提供全局网络和设备信息的单例管理,避免重复检测。

使用方法

import {
  getGlobalNetworkInfo,
  getGlobalDeviceInfo,
  getGlobalContextStats,
  addGlobalContextListener,
} from "vane-lazy-image";

// 获取网络信息(自动缓存)
const networkInfo = getGlobalNetworkInfo();
console.log(networkInfo);
// {
//   effectiveType: "4g",
//   downlink: 10,
//   rtt: 50,
//   saveData: false
// }

// 获取设备信息(自动缓存)
const deviceInfo = getGlobalDeviceInfo();
console.log(deviceInfo);
// {
//   type: "desktop",
//   os: "Windows",
//   browser: "Chrome",
//   devicePixelRatio: 2,
//   viewportWidth: 1920,
//   viewportHeight: 1080
// }

// 监听全局上下文变化
const unsubscribe = addGlobalContextListener((context) => {
  console.log("全局上下文更新", context);
});

// 获取统计信息
const stats = getGlobalContextStats();
console.log(stats);
// {
//   listenersCount: 5,
//   updateCount: 10,
//   hasCache: true,
//   cacheAge: 1500
// }

// 取消监听
unsubscribe();

优势

  • 减少 99% 检测次数 - 100 个组件从 200 次检测减少到 2 次
  • 自动缓存 - 网络/设备信息自动缓存,无需重复检测
  • 事件驱动 - 网络/窗口变化时自动通知所有订阅者
  • 零配置 - 自动初始化,开箱即用

ObserverPool - IntersectionObserver 共享池

ObserverPool 实现 IntersectionObserver 实例的共享,大幅减少内存占用。

使用方法

import {
  observeElement,
  unobserveElement,
  getObserverPoolStats,
  setObserverPoolDebugMode,
  cleanupObserverPool,
} from "vane-lazy-image";

// 观察元素(自动共享 Observer)
const element = document.querySelector(".my-image");
observeElement(
  element,
  (entry) => {
    console.log("元素可见性变化", entry.isIntersecting);
  },
  {
    rootMargin: "0px",
    threshold: 0.1,
  }
);

// 取消观察
unobserveElement(element);

// 获取池统计信息
const stats = getObserverPoolStats();
console.log(stats);
// {
//   observerCount: 1,
//   elementCount: 100,
//   efficiency: 99,
//   memoryEstimate: "10.77 kB",
//   callbackExecutions: 150
// }

// 启用调试模式
setObserverPoolDebugMode(true);

// 手动清理空闲 Observer
cleanupObserverPool();

优势

  • 减少 99% Observer 实例 - 100 个元素从 100 个 Observer 减少到 1 个
  • 自动管理 - 相同配置的元素自动共享 Observer
  • 内存优化 - 内存占用从 1077 kB 减少到 10.77 kB
  • 自动清理 - 60秒自动清理空闲 Observer

综合使用示例

import {
  LazyLoadImageCore,
  withPlugins,
  createFadeInPlugin,
  getGlobalNetworkInfo,
  getObserverPoolStats,
} from "vane-lazy-image";

function PerformanceOptimizedComponent() {
  // 组件会自动使用 GlobalContext 和 ObserverPool
  const LazyImage = withPlugins(LazyLoadImageCore, [
    createFadeInPlugin({ durationMs: 600 }),
  ]);

  // 可以手动获取优化效果
  const networkInfo = getGlobalNetworkInfo();
  const poolStats = getObserverPoolStats();

  console.log("性能优化效果", {
    network: networkInfo.effectiveType,
    observerEfficiency: `${poolStats.efficiency}%`,
    memoryReduction: `${poolStats.memoryEstimate}`,
  });

  return (
    <div>
      {Array.from({ length: 100 }).map((_, i) => (
        <LazyImage
          key={i}
          src={`https://picsum.photos/seed/${i}/800/600`}
          alt={`图片 ${i + 1}`}
          loading="lazy"
          containerStyle={{ width: 320, height: 200 }}
          imageStyle={{ width: "100%", height: "100%", objectFit: "cover" }}
        />
      ))}
    </div>
  );
}

💡 查看完整演示:访问 性能优化综合示例 查看实时性能对比


🔨 自定义插件开发

创建自定义插件非常简单,只需实现 LazyImagePlugin 接口:

基础插件示例

import type { LazyImagePlugin } from "vane-lazy-image";

interface MyPluginOptions {
  message?: string;
  showOverlay?: boolean;
}

export function createMyCustomPlugin(
  options: MyPluginOptions = {}
): LazyImagePlugin {
  const { message = "自定义插件", showOverlay = true } = options;

  return {
    name: "my-custom-plugin",
    version: "1.0.0",
    config: options,

    // 插件初始化
    init: async () => {
      console.log(`${message} 初始化`);
    },

    // 插件销毁
    destroy: async () => {
      console.log(`${message} 销毁`);
    },

    // 插件钩子
    hooks: {
      // 组件挂载时
      onMount: (context) => {
        console.log("组件挂载", context.src);

        // 返回清理函数(可选)
        return () => {
          console.log("组件卸载清理");
        };
      },

      // 加载前检查
      onBeforeLoad: (context) => {
        console.log("准备加载", context.src);
        // 返回 false 可以阻止加载
        return true;
      },

      // 修改图片源
      onLoad: (context) => {
        // 可以返回修改后的 src
        return context.src + "?custom=param";
      },

      // 加载成功
      onLoadSuccess: (context, displaySrc) => {
        console.log("加载成功", displaySrc);
      },

      // 加载失败
      onLoadError: (context, error) => {
        console.error("加载失败", error);
        // 返回 true 表示已处理错误
        return true;
      },

      // 进入视口
      onEnterViewport: (context) => {
        console.log("进入视口");
      },

      // 离开视口
      onLeaveViewport: (context) => {
        console.log("离开视口");
      },

      // 加载进度
      onProgress: (context, progress) => {
        console.log(`加载进度: ${progress.percent}%`);
      },

      // 渲染覆盖层
      renderOverlay: (context) => {
        if (!showOverlay) return null;

        return (
          <div
            style={{
              position: "absolute",
              top: 0,
              left: 0,
              right: 0,
              bottom: 0,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              background: "rgba(0, 0, 0, 0.5)",
              color: "white",
              pointerEvents: "none",
            }}
          >
            {message}
          </div>
        );
      },
    },
  };
}

插件开发最佳实践

1. 命名规范

// ✅ 好的命名
export function createWatermarkPlugin(options) { ... }
export function createRetryOnErrorPlugin(options) { ... }

// ❌ 避免的命名
export function watermark(options) { ... }
export function plugin(options) { ... }

2. 错误处理

hooks: {
  onLoadError: (context, error) => {
    try {
      // 处理错误
      console.error("插件错误", error);

      // 返回 true 表示已处理
      return true;
    } catch (e) {
      // 避免插件错误影响其他插件
      console.warn("错误处理失败", e);
      return false;
    }
  },
}

3. 清理资源

hooks: {
  onMount: (context) => {
    const timer = setInterval(() => {
      // 定期任务
    }, 1000);

    // 返回清理函数
    return () => {
      clearInterval(timer);
    };
  },
}

4. 使用插件总线

hooks: {
  onMount: (context) => {
    // 订阅事件
    const unsubscribe = context.bus?.on("custom-event", (data) => {
      console.log(data);
    });

    // 发送事件
    context.bus?.emit("plugin-ready", { name: "my-plugin" });

    // 共享数据
    context.bus?.setData("myKey", "myValue");

    return unsubscribe;
  },
}

💡 使用技巧

1. 组合多个视觉效果

const LazyImage = withPlugins(LazyLoadImageCore, [
  createSkeletonPlugin({ type: "shimmer" }),
  createBlurUpPlugin({ blurAmount: 20 }),
  createFadeInPlugin({ durationMs: 600 }),
  createWatermarkPlugin({ text: "VANE" }),
]);

2. 性能优化最佳实践

const LazyImage = withPlugins(LazyLoadImageCore, [
  createPreconnectPlugin({ domains: ["https://cdn.example.com"] }),
  createCacheMemoryPlugin({ maxSize: 50 }),
  createConcurrencyControlPlugin({ maxConcurrent: 4 }),
  createImageOptimizationPlugin({ defaultQuality: 80 }),
]);

3. 错误处理完整方案

const LazyImage = withPlugins(LazyLoadImageCore, [
  createRetryOnErrorPlugin({ maxRetries: 3 }),
  createCDNFallbackPlugin({ fallbackUrls: ["https://backup.cdn.com"] }),
  createFallbackImagePlugin({ fallbackSrc: "/404.jpg" }),
  createErrorOverlayPlugin({ showRetryButton: true }),
]);

❓ 常见问题

Q: "Loading..." 文本没有居中?

A: 确保容器使用了正确的定位方式。推荐使用绝对定位 + Flexbox:

containerStyle={{
  position: "relative",
  width: "100%",
  height: "100%",
}}

覆盖层样式:

position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;

Q: 插件热更新不生效?

A: 确保:

  1. PluginManager.register()unregister() 返回 boolean
  2. 使用 manager.getActivePlugins() 获取当前插件列表
  3. 重新创建带新插件的组件实例

Q: 如何调试插件?

A: 使用 createEventLoggerPlugin

const LazyImage = withPlugins(LazyLoadImageCore, [
  createEventLoggerPlugin(),
  // 其他插件...
]);

Q: 如何在生产环境中使用?

A: 安装 npm 包后直接导入:

import {
  LazyLoadImageCore,
  withPlugins,
  createWatermarkPlugin,
} from "vane-lazy-image";

Q: TypeScript 类型报错?

A: 确保安装了类型定义:

// 类型已内置,如果仍有报错,可以临时使用类型断言
const LazyImage = withPlugins(LazyLoadImageCore, plugins);

🌐 浏览器支持

| 浏览器 | 版本 | | ------- | ---- | | Chrome | ≥ 88 | | Firefox | ≥ 85 | | Safari | ≥ 14 | | Edge | ≥ 88 |

对于不支持 IntersectionObserver 的老旧浏览器,组件会自动降级为立即加载模式。


🛠️ 技术栈

  • 框架:React 18+
  • 语言:TypeScript 5+
  • 构建工具:Vite 5+
  • 样式:CSS-in-JS(内联样式)
  • 代码高亮:react-syntax-highlighter
  • 路由:react-router-dom
  • 缓存:localforage (IndexedDB)

🤝 贡献指南

欢迎提交 Issue 和 Pull Request!

开发流程

  1. Fork 本仓库
  2. 创建特性分支:git checkout -b feature/your-feature
  3. 提交更改:git commit -m "Add some feature"
  4. 推送到分支:git push origin feature/your-feature
  5. 提交 Pull Request

代码规范

  • 使用 ESLint 进行代码检查
  • 遵循 TypeScript 严格模式
  • 保持代码简洁、可读
  • 为新功能添加测试和文档

📄 许可证

MIT License © 2025 Frank Vane


🔗 相关链接


🙏 致谢

感谢所有为这个项目做出贡献的开发者!

如果这个项目对您有帮助,欢迎 ⭐ Star 支持!


Made with ❤️ by Frank Vane