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

React中自定义GIF作为加载图标及居中显示问题求助

问题解决步骤

1. 修复自定义GIF路径问题

React中静态资源路径有两种正确处理方式:

  • 方式一:将GIF放在public目录
    创建public/loading-images文件夹,把所有GIF放进去,此时路径直接写/loading-images/l1.gif(public是项目的静态资源根目录,浏览器会直接从根路径读取)。
  • 方式二:在src中导入图片
    如果GIF放在src/components/loading-images,需要逐个导入:
    import l1 from './loading-images/l1.gif'
    import l2 from './loading-images/l2.gif'
    // ... 导入其他GIF
    const loadingGifsList = [l1, l2, l3, ...]
    

2. 重构LoadingPage组件(替换react-loading,实现居中)

react-loading组件主要用于预设加载动画,自定义图片直接用<img>更直观,同时添加CSS实现全屏居中:

import { useState, useEffect } from 'react'

// 这里根据你选择的路径方式修改数组
const loadingGifsList = [
    '/loading-images/l1.gif',
    '/loading-images/l2.gif',
    '/loading-images/l3.gif',
    // ... 其他GIF路径
]

const LoadingPage = ({ isLoading, setIsLoading, minDisplayTime = 5000 }) => {
    const [selectedGif] = useState(loadingGifsList[Math.floor(Math.random() * loadingGifsList.length)])

    useEffect(() => {
        // 确保至少显示指定时长的加载动画
        const timeout = setTimeout(() => {
            setIsLoading(false)
        }, minDisplayTime)
        
        return () => clearTimeout(timeout)
    }, [setIsLoading, minDisplayTime])

    if (!isLoading) return null

    return (
        <div style={{
            position: 'fixed',
            top: 0,
            left: 0,
            width: '100vw',
            height: '100vh',
            backgroundColor: '#fff',
            display: 'flex',
            justifyContent: 'center',
            alignItems: 'center',
            zIndex: 9999
        }}>
            <img src={selectedGif} alt="加载中" style={{ maxWidth: '80%', maxHeight: '80%' }} />
        </div>
    )
}

export default LoadingPage

3. 修正App.js的加载逻辑

结合API请求完成和最小显示时长,确保加载动画至少展示5秒,同时控制页面内容的显示:

import axios from 'axios'
import { useState, useEffect } from 'react'
import Header from './components/Header.js'
import Add from './components/Add.js'
import Rules from './components/Rules.js'
import Select from './components/SelectGame'
import Player from './components/PlayerSelect.js'
import Board1 from './components/Player1_Board'
import Board2 from './components/Player2_Board'
import 'bootstrap/dist/css/bootstrap.min.css';
import IndexCSS from './index.module.css';
import LoadingPage from './components/Loading.js'

const App = () => {
  const [games, setGames] = useState([])
  const [showAdd, setAdd] = useState(false)
  const [showRules, setRules] = useState(true)
  const [showSelect, setSelect] = useState(false)
  const [currentGameID, setCurrentGameID] = useState('')
  const [playerSelect, setPlayerSelect] = useState(true)
  const [showP1, setP1] = useState(false)
  const [showP2, setP2] = useState(false)
  const [isLoading, setIsLoading] = useState(true)

  const handleDelete = (event) => {
    axios.delete('https://connect4back.herokuapp.com/api/connect4/' + event.id).then((response) => {
      getGames();
    })
  }

  const handleUpdate = (game) => {
    axios.put('https://connect4back.herokuapp.com/api/connect4/' + game.id, game).then((response) => {
      getGames();
    })
  }

  const handleCreate = (add) => {
    axios.post('https://connect4back.herokuapp.com/api/connect4', add).then((response) => {
      getGames();
    })
  }

  const getGames = () => {
    return axios.get('https://connect4back.herokuapp.com/api/connect4').then((response) => {
      setGames(response.data)
    })
  }

  useEffect(() => {
    // 并行处理API请求和最小显示时长,取最晚完成的那个结束加载
    const fetchData = async () => {
      await Promise.all([
        getGames(),
        new Promise(resolve => setTimeout(resolve, 5000))
      ])
      setIsLoading(false)
    }
    fetchData()
  }, [])

  // 加载中只显示LoadingPage,否则显示页面内容
  if (isLoading) {
    return <LoadingPage isLoading={isLoading} setIsLoading={setIsLoading} />
  }

  return (
    <div className={IndexCSS.appContainer}>
      <Header setAdd={setAdd} setRules={setRules} setSelect={setSelect} setCurrentGameID={setCurrentGameID} setP1={setP1} setP2={setP2}/>
      <div key={games.id}>
        {showRules && <Rules setRules={setRules}/>}
        {showAdd && <Add handleCreate={handleCreate} setAdd={setAdd} setSelect={setSelect}/>}
        {showSelect && <Select games={games} setSelect={setSelect} setCurrentGameID={setCurrentGameID} setPlayerSelect={setPlayerSelect}/>}
        {games.map((game) => {
          if (game.id === currentGameID) {
            return (
              <div key={game.id}>
                {playerSelect && <Player game={game} setP1={setP1} setP2={setP2} setSelect={setSelect} setPlayerSelect={setPlayerSelect}/>}
                {showP1 && <Board1 game1={game} handleDelete={handleDelete} handleUpdate={handleUpdate} />}
                {showP2 && <Board2 game2={game} handleDelete={handleDelete} handleUpdate={handleUpdate} />}
              </div>
            )
          }
          return null
        })}
      </div>
    </div>
  )
}

export default App

关键说明

  • 去掉react-loading组件,直接用<img>避免组件对自定义图片的支持问题;
  • 加载容器使用fixed定位+flex布局实现全屏居中,zIndex确保在最上层;
  • 用Promise.all结合API请求和5秒超时,保证加载动画至少展示5秒,同时等待API请求完成,避免内容未加载完就显示;
  • 简化条件渲染写法(用&&替代三元表达式);
  • App中统一控制isLoading状态,确保加载时只显示加载动画,结束后显示完整内容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 22:55:39