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
相关产品推荐
相关产品推荐

