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

@fly4react/image

v1.12.2

Published

Image optimization and lazy loading utilities for React

Readme

@fly4react/image

为 React 应用程序提供图片优化和懒加载工具,支持 SSR。

📖 English Documentation: View English Version

安装

npm install @fly4react/image
# 或
yarn add @fly4react/image
# 或
pnpm add @fly4react/image

特性

  • 🖼️ 图片懒加载 - 仅在图片进入视口时加载
  • 🚀 性能优化 - 减少初始页面加载时间
  • 📱 响应式图片 - 支持不同屏幕尺寸
  • 🎯 Intersection Observer - 现代浏览器 API 高效检测
  • 🔧 TypeScript 支持 - 完整的类型安全
  • 🌐 SSR 支持 - 服务端渲染与预加载优化
  • 图片预加载 - 预加载关键图片提升性能
  • 🔄 基于 Context 的架构 - 灵活的预加载队列管理
  • 📦 自定义队列实现 - 提供你自己的预加载队列逻辑

使用方法

基础图片加载

import { ImageLoader } from '@fly4react/image';

function MyComponent() {
  return (
    <div>
      {/* 内容图片 */}
      <ImageLoader 
        type="content"
        src="https://example.com/image.jpg" 
        alt="我的图片"
        lazyload={true}
      />
      
      {/* 背景图片 */}
      <ImageLoader 
        type="background"
        src="https://example.com/background.jpg"
        style={{ width: '100%', height: '200px' }}
      >
        <h1>背景上的内容</h1>
      </ImageLoader>
    </div>
  );
}

基于 Context 架构的图片预加载

import { 
  ImageLoader, 
  PreloadQueueProvider,
  ImagePreloadConsumer,
  BackgroundImage,
  ContentImage
} from '@fly4react/image';

// 自定义预加载队列实现
class MyPreloadQueue {
  private images = [];

  addImage(options) {
    this.images.push(options);
  }

  getImages() {
    return this.images;
  }

  clearImages() {
    this.images.length = 0;
  }
}

function MyComponent() {
  return (
    <PreloadQueueProvider value={new MyPreloadQueue()}>
      <ImageLoader 
        type="content"
        src="https://example.com/critical-image.jpg"
        preloadConfig={{
          preload: true,
          priority: 'high',
          type: 'image/jpeg',
          ssr: true,
        }}
        alt="关键图片"
      />
      
      {/* 或使用独立组件 */}
      <ContentImage
        src="https://example.com/content.jpg"
        preloadConfig={{
          preload: true,
          priority: 'auto',
          ssr: true,
        }}
        alt="内容图片"
      />
      
      <BackgroundImage
        src="https://example.com/background.jpg"
        preloadConfig={{
          preload: true,
          priority: 'low',
          ssr: true,
        }}
        style={{ width: '100%', height: '200px' }}
      >
        <h1>背景内容</h1>
      </BackgroundImage>
      
      {/* 渲染预加载链接 */}
      <ImagePreloadConsumer />
    </PreloadQueueProvider>
  );
}

高级 Context 配置

新的基于 Context 的架构允许你为不同场景提供自定义预加载队列实现:

import { 
  PreloadQueueProvider,
  AddToPreloadProvider,
  GetPreloadImagesProvider,
  ClearPreloadProvider,
  useAddToPreloadQueue,
  useGetPreloadImages,
  useClearPreloadQueue
} from '@fly4react/image';

// 基于内存的队列(默认)
class MemoryQueue {
  private images = [];

  addImage(options) {
    this.images.push(options);
  }

  getImages() {
    return [...this.images];
  }

  clearImages() {
    this.images.length = 0;
  }
}

// 请求作用域队列(用于 SSR)
class RequestQueue {
  constructor(requestId) {
    this.requestId = requestId;
    this.images = [];
  }

  addImage(options) {
    this.images.push({ ...options, requestId: this.requestId });
  }

  getImages() {
    return this.images.filter(img => img.requestId === this.requestId);
  }

  clearImages() {
    this.images = this.images.filter(img => img.requestId !== this.requestId);
  }
}

// 带持久化的自定义队列
class PersistentQueue {
  constructor(storage) {
    this.storage = storage;
  }

  addImage(options) {
    const images = this.storage.getItem('preloadImages') || [];
    images.push(options);
    this.storage.setItem('preloadImages', images);
  }

  getImages() {
    return JSON.parse(this.storage.getItem('preloadImages') || '[]');
  }

  clearImages() {
    this.storage.removeItem('preloadImages');
  }
}

// 使用不同队列类型
function App() {
  // 内存队列(默认)
  const memoryQueue = new MemoryQueue();
  
  // 请求作用域队列(用于 SSR)
  const requestQueue = new RequestQueue(req.id);
  
  // 持久化队列
  const persistentQueue = new PersistentQueue(localStorage);

  return (
    <PreloadQueueProvider value={memoryQueue}>
      <MyComponent />
    </PreloadQueueProvider>
  );
}

图片 URL 转换

import { ImageLoader } from '@fly4react/image';

function MyComponent() {
  // 自定义转换函数 - 根据你的 CDN 提供商实现
  const toWebP = (src: string) => src.replace(/\.(jpg|jpeg|png)$/i, '.webp');
  const addSize = (width: number, height?: number) => (src: string) => 
    `${src}?w=${width}${height ? `&h=${height}` : ''}`;
  
  return (
    <div>
      {/* 转换为 WebP 格式 */}
      <ImageLoader 
        type="content"
        src="https://example.com/image.jpg"
        transform={toWebP}
        alt="WebP 图片"
      />
      
      {/* 添加尺寸参数 */}
      <ImageLoader 
        type="background"
        src="https://example.com/background.png"
        transform={addSize(800, 600)}
        style={{ width: '100%', height: '200px' }}
      >
        <h1>调整尺寸的背景</h1>
      </ImageLoader>
      
      {/* 组合转换 */}
      <ImageLoader 
        type="content"
        src="https://example.com/image.jpg"
        transform={(src) => addSize(800)(toWebP(src))}
        alt="转换后的图片"
      />
    </div>
  );
}

灵活的预加载渲染

import { ImagePreloadConsumer } from '@fly4react/image';

// 方法 1: 在 head 中渲染
function HeadPreload() {
  return (
    <head>
      <title>我的应用</title>
      <ImagePreloadConsumer />
    </head>
  );
}

// 方法 2: 在 body 中渲染
function BodyPreload() {
  return (
    <body>
      <ImagePreloadConsumer />
      <div id="app">...</div>
    </body>
  );
}

// 方法 3: 在任何地方渲染
function CustomPreload() {
  return (
    <div>
      <ImagePreloadConsumer />
      <main>...</main>
    </div>
  );
}

// 方法 4: 条件渲染
function ConditionalPreload() {
  return (
    <div>
      {process.env.NODE_ENV === 'production' && (
        <ImagePreloadConsumer />
      )}
      <main>...</main>
    </div>
  );
}

Next.js 集成

// pages/_document.tsx
import Document, { Html, Head, Main, NextScript } from 'next/document';
import { ImagePreloadConsumer } from '@fly4react/image';

class MyDocument extends Document {
  render() {
    return (
      <Html>
        <Head>
          {/* 在 head 中渲染预加载链接 */}
          <ImagePreloadConsumer />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;

API

ImageLoader

根据 type 属性渲染不同类型图片的组件。

<ImageLoader 
  type="content" | "background"  // 图片类型
  {...props}                     // 对应类型的属性
/>

// 使用 forwardRef
const imageRef = useRef<HTMLImageElement | HTMLDivElement>(null);

<ImageLoader 
  ref={imageRef}
  type="content"
  src="https://example.com/image.jpg"
  alt="我的图片"
/>

ImagePreloadConsumer

在 SSR 环境中渲染预加载 <link> 标签的组件。

<ImagePreloadConsumer 
  ssr={boolean}                    // 是否在 SSR 中渲染
/>

Context Providers

PreloadQueueProvider

组合所有预加载功能的主提供者。

<PreloadQueueProvider value={yourQueue}>
  {children}
</PreloadQueueProvider>

独立提供者

为了性能优化,你可以使用独立的提供者:

<AddToPreloadProvider addImage={addImageFunction}>
  <GetPreloadImagesProvider getImages={getImagesFunction}>
    <ClearPreloadProvider clearImages={clearImagesFunction}>
      {children}
    </ClearPreloadProvider>
  </GetPreloadImagesProvider>
</AddToPreloadProvider>

Hooks

useAddToPreloadQueue

用于向预加载队列添加图片的 Hook。

const addToPreloadQueue = useAddToPreloadQueue();

// 向队列添加图片
addToPreloadQueue({
  src: 'https://example.com/image.jpg',
  priority: 'high',
  type: 'image/jpeg',
  ssr: true,
});

useGetPreloadImages

用于从预加载队列获取图片的 Hook。

const getPreloadImages = useGetPreloadImages();

// 获取队列中的所有图片
const images = getPreloadImages();

useClearPreloadQueue

用于清空预加载队列的 Hook。

const clearPreloadQueue = useClearPreloadQueue();

// 清空队列中的所有图片
clearPreloadQueue();

预加载配置

interface PreloadConfig {
  preload?: boolean;              // 是否启用预加载
  priority?: 'high' | 'low' | 'auto'; // 预加载优先级
  type?: string;                  // 图片类型
  ssr?: boolean;                  // 是否在 SSR 中预加载
  sizes?: string;                 // 图片尺寸信息
  media?: string;                 // 媒体查询
}

独立组件

BackgroundImage

支持预加载的背景图片组件。

<BackgroundImage
  src="https://example.com/background.jpg"
  preloadConfig={{
    preload: true,
    priority: 'low',
    ssr: true,
  }}
  style={{ width: '100%', height: '200px' }}
>
  <h1>背景上的内容</h1>
</BackgroundImage>

ContentImage

支持预加载和懒加载的内容图片组件。

<ContentImage
  src="https://example.com/content.jpg"
  preloadConfig={{
    preload: true,
    priority: 'auto',
    ssr: true,
  }}
  lazyload={true}
  alt="内容图片"
/>

从 v1.x 迁移

如果你正在从 v1.x 升级,以下是主要变更:

破坏性变更

  1. 移除了兼容模式:不再支持 compatibilityMode 属性
  2. 新的 Context 架构:预加载功能现在需要 Context 提供者
  3. 重命名属性preload 属性现在是 preloadConfig
  4. 新的类型名称ImagePreloadOptions 现在是 PreloadConfig

迁移步骤

  1. 用 PreloadQueueProvider 包装你的应用
// 之前
<MyApp />

// 之后
<PreloadQueueProvider value={new MyPreloadQueue()}>
  <MyApp />
</PreloadQueueProvider>
  1. 更新属性名称
// 之前
<ImageLoader 
  preload={{
    priority: 'high',
    ssr: true,
  }}
/>

// 之后
<ImageLoader 
  preloadConfig={{
    preload: true,
    priority: 'high',
    ssr: true,
  }}
/>
  1. 更新 ImagePreloadConsumer
// 之前
<ImagePreloadConsumer compatibilityMode="legacy" />

// 之后
<ImagePreloadConsumer />

许可证

MIT