You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js图片加载优化:预加载图片提升性能

解决Next.js滚动图片加载性能问题的预加载方案

核心思路

提前把所有需要的图片预加载到浏览器缓存,避免滚动时动态加载引发的卡顿;同时优化滚动事件处理逻辑,减少组件不必要的重渲染次数。

具体实现步骤

1. 添加图片预加载逻辑

组件挂载时,循环生成所有图片路径(从0.png到180.png),通过原生Image对象完成预加载,确保滚动时图片已在本地缓存中:

useEffect(() => {
  // 预加载所有图片资源
  const preloadImages = () => {
    for (let i = 0; i <= 180; i++) {
      const img = new Image();
      img.src = `/headphone/${i}.png`;
    }
  };

  preloadImages();

  // 滚动事件处理(后续优化防抖)
  const handleScroll = () => {
    const scrollPercentage = (window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)) * 180;
    setHeadphones(scrollPercentage);
  };

  window.addEventListener('scroll', handleScroll);

  return () => {
    window.removeEventListener('scroll', handleScroll);
  };
}, []);

2. 防抖优化滚动事件

滚动事件会高频触发,添加防抖函数减少setState调用频率,降低组件重渲染压力:

// 防抖工具函数
const debounce = (func: Function, delay: number) => {
  let timeoutId: NodeJS.Timeout;
  return (...args: any[]) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, args), delay);
  };
};

// 在useEffect中替换为防抖后的处理函数
useEffect(() => {
  // ...预加载逻辑保持不变

  const debouncedHandleScroll = debounce(() => {
    const scrollPercentage = (window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)) * 180;
    setHeadphones(scrollPercentage);
  }, 16); // 约60fps间隔,平衡响应性和性能

  window.addEventListener('scroll', debouncedHandleScroll);

  return () => {
    window.removeEventListener('scroll', debouncedHandleScroll);
  };
}, []);

3. 简化Image组件配置

预加载完成后,无需自定义loader,直接使用生成的imagePath作为src即可;同时移除priority属性(预加载已提前完成资源加载):

// 移除原有的imageLoader函数
const imagePath = `/headphone/${Math.round(headphones)}.png`;

// 修改后的Image组件
<Image
  src={imagePath}
  alt={`Headphone image ${Math.round(headphones)}`}
  width={1920}
  height={1080}
  className='w-[calc(100vw-7px)] absolute z-10'
/>

完整修改后的代码

'use client'

import Image from 'next/image';
import { useEffect, useState } from 'react';

export default function Home() {
  const [headphones, setHeadphones] = useState(0);

  // 防抖工具函数
  const debounce = (func: Function, delay: number) => {
    let timeoutId: NodeJS.Timeout;
    return (...args: any[]) => {
      clearTimeout(timeoutId);
      timeoutId = setTimeout(() => func.apply(this, args), delay);
    };
  };

  useEffect(() => {
    // 预加载所有图片
    const preloadImages = () => {
      for (let i = 0; i <= 180; i++) {
        const img = new Image();
        img.src = `/headphone/${i}.png`;
      }
    };

    preloadImages();

    const debouncedHandleScroll = debounce(() => {
      const scrollPercentage = (window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)) * 180;
      setHeadphones(scrollPercentage);
    }, 16);

    window.addEventListener('scroll', debouncedHandleScroll);

    return () => {
      window.removeEventListener('scroll', debouncedHandleScroll);
    };
  }, []);

  const imagePath = `/headphone/${Math.round(headphones)}.png`;

  return (
    <main className='h-[100vh] w-[100vw] sticky top-0 flex flex-col justify-center items-center'>  
      <Image
        src={imagePath}
        alt={`Headphone image ${Math.round(headphones)}`}
        width={1920}
        height={1080}
        className='w-[calc(100vw-7px)] absolute z-10'
      />
      <div className='w-[100vw] flex flex-col items-end'>
        <div className='flex flex-col items-center'>
          <h1 className={`title text-center w-[7ch] m-[5rem] transition-fade-in ${headphones >= 19 ? 'hidden' : ''}`}>IMMERSE IT IN</h1>
          <p className={`buy transition-fade-in bg-[red] w-[15rem] rounded-full  ${headphones >= 19 ? 'hidden' : ''}`}>BUY</p>
        </div>
      </div>
      <p className={`w-[15ch] transition-fade-in ${headphones <= 16 ? 'hidden' : headphones >= 25 && headphones <= 40 ? 'absolute right-0 bottom-[10%] m-24' : 'hidden'}`}><b className='font-300'>Noise reduction technology</b> for the Best immersion.</p>
      <p className={`w-[18ch] transition-fade-in ${headphones <= 16 ? 'hidden' : headphones >= 25 && headphones <= 40 ? 'absolute left-0 w-[22ch] text-left m-24' : 'hidden'}`}><b  className='font-300'>Talk</b> instead of typing with our <b  className='font-300'>IA powered</b> assistent. <b  className='font-300'>Just ask.</b></p>
      
      <p className={`w-[21ch] transition-fade-in ${headphones <= 16 ? 'hidden' : headphones >= 50 && headphones <= 70 ? 'absolute right-0 bottom-[10%] m-24' : 'hidden'}`}>Revolutionary <b className='font-300'>charging technology</b>. Stay <b className='font-300'>connected</b>.</p>
      <p className={` transition-fade-in ${headphones <= 16 ? 'hidden' : headphones >= 50 && headphones <= 70 ? 'absolute left-0 top-0 w-[20ch] text-left m-24' : 'hidden'}`}><b className='font-300'>Charge in minutes</b> and <b className='font-300'>use for days.</b></p>
      <p className={` transition-fade-in ${headphones <= 16 ? 'hidden' : headphones >= 50 && headphones <= 70 ? 'absolute left-0 top-0 w-[20ch] text-left m-24' : 'hidden'}`}><b className='font-300'>Charge in minutes</b> and <b className='font-300'>use for days.</b></p>

      <div className='w-[100vw] flex flex-col items-center'>
        <p className={`text-center w-[100vw] text-[200px] transition-fade-in ${headphones <= 16 ? 'hidden' : headphones >= 70 && headphones <= 100 ? '' : 'hidden'}`}>Connect <b  className='font-300'>Anywhere</b> on <b  className='font-300'>anything</b>.</p>
        <p className={`text-center w-[100vw] text-[50px] transition-fade-in ${headphones <= 16 ? 'hidden' : headphones >= 70 && headphones <= 100 ? '' : 'hidden'}`}>Integrated Adapters for all your devices.</p>
      </div>      
      <p className={` transition-fade-in ${headphones <= 16 ? 'hidden' : headphones >= 100 && headphones <= 160 ? 'absolute right-0 bottom-0 w-[15ch] text-[150px] text-right m-24' : 'hidden'}`}><b  className='font-300'>2 GB</b> of <b  className='font-300'>memory. Never stop vibing.</b>
      </p>
      <div className='w-[100vw] flex flex-col items-center'>
        <p className={`absolute text-center w-[100vw] text-[150px] tstroke transition-fade-in ${headphones <= 16 ? 'hidden' : headphones >= 160 ? 'transition-fade-out' : 'hidden'}`}><b className='font-300'>Bluethoth Integrated.</b></p>
        <p className={`text-center w-[100vw] text-[150px] transition-fade-in ${headphones <= 16 ? 'hidden' : headphones >= 160 ? '' : 'hidden'}`}><b className='font-300'>Bluethoth Integrated.</b></p>
      </div>  
    </main>
  )
}

内容的提问来源于stack exchange,提问作者user22857802

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 17:42:04