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

React(MUI)桌面页面正常加载,移动端仅显示Loader组件求助

问题:React + MUI 页面移动端始终停留在Loader,桌面端正常

我有一个使用MUI组件的React页面,主App代码如下:

// Theme and other components
import React, { useEffect, useState, lazy, Suspense, MouseEvent } from 'react';
import Box from "@mui/material/Box";
import { createTheme, ThemeProvider } from "@mui/material";
import ErrorBoundary from "../ErrorHandler/ErrorBoundary";
import Loader from "../Components/HelperComps/Loader";
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';

// Header / Footer
import ResponsiveAppBar from "../Components/HeaderFooter/ResponsiveAppBar";
import Footer from "../Components/HeaderFooter/Footer";
import WaterEffect from "../Components/HelperComps/WaterEffect/WaterEffect";
import {BANANA_CURSOR, MUSIC_MOUSE} from "../Stuff/ImagePaths";

// Pages (lazy loading)
const Home = lazy(() => import("../Components/Pages/Home"));
const Live = lazy(() => import("../Components/Pages/Live"));
const Studio = lazy(() => import("../Components/Pages/Studio"));
const Aktuell = lazy(() => import("../Components/Pages/Zeit/Aktuell"));
const Vergangenheit = lazy(() => import("../Components/Pages/Zeit/Vergangenheit"));
const Zukunft = lazy(() => import("../Components/Pages/Zeit/Zukunft"));
const Genesis = lazy(() => import("../Components/Pages/Zeit/Genesis"));
const Kontakt = lazy(() => import("../Components/HeaderFooter/FooterSites/Kontakt"));
const Datenschutz = lazy(() => import("../Components/HeaderFooter/FooterSites/Datenschutz"));
const Impressum = lazy(() => import("../Components/HeaderFooter/FooterSites/Impressum"));
const ErrorPage = lazy(() => import("../ErrorHandler/ErrorPage"));

// create a theme instance
const theme = createTheme({
    components: {
        MuiAppBar: {
            styleOverrides: {
                root: {
                    height: '9vh',
                },
            },
        },
    },
});

interface MousePosition {
    x: number;
    y: number;
}

const App: React.FC = () => {
    const [loading, setLoading] = useState<boolean>(true);
    const [mousePos, setMousePos] = useState<MousePosition>({ x: 0, y: 0 });

    useEffect(() => {
        const minLoadingTime = 1000; // 1 second minimum loading time
        const startTime = Date.now();

        const handleLoad = () => {
            const elapsedTime = Date.now() - startTime;
            const remainingTime = minLoadingTime - elapsedTime;

            if (remainingTime > 0) {
                setTimeout(() => {
                    setLoading(false);
                }, remainingTime);
            } else {
                setLoading(false);
            }
        };

        // Adding event listener for when the entire page has loaded
        window.addEventListener('load', handleLoad);

        // Cleanup event listener on component unmount
        return () => {
            window.removeEventListener('load', handleLoad);
        };
    }, []);

    const handleMouseMove = (event: MouseEvent<HTMLDivElement>) => {
        setMousePos({ x: event.clientX + window.scrollX, y: event.clientY + window.scrollY });
    };

    return (
        <ThemeProvider theme={theme}>
            <ErrorBoundary>
                <Router>
                    <Box
                        // onMouseMove={handleMouseMove}
                        sx={{
                            minHeight: '100 vh',
                            paddingBottom: '9vh',
                            paddingTop: '9vh',
                            position: 'relative',
                            overflow: 'hidden',
                            cursor: `url(${MUSIC_MOUSE}) 16 16, auto`,
                            /*'&::after': {
                                content: '""',
                                width: 100,
                                height: 100,
                                background: 'radial-gradient(circle, rgba(255, 255, 0, 1) 0%, rgba(255, 255, 0, 0.8) 25%, rgba(255, 255, 0, 0.4) 50%, rgba(255, 255, 0, 0.2) 75%, rgba(255, 255, 0, 0) 100%)',
                                borderRadius: '50%',
                                position: 'absolute',
                                top: mousePos.y,
                                left: mousePos.x,
                                pointerEvents: 'none', // Ensure the effect doesn't interfere with pointer events
                                transform: 'translate(-50%, -50%)', // Center the effect exactly at the cursor
                            },*/
                        }}
                    >
                        {loading && <Loader />}
                        {!loading && (
                            <>
                                <ResponsiveAppBar />
                                <Suspense fallback={<Loader />}>
                                    <Routes>
                                        <Route path="/" element={<Home />} />
                                        <Route path="/zeit/genesis" element={<Genesis />} />
                                        <Route path="/zeit/vergangenheit" element={<Vergangenheit />} />
                                        <Route path="/zeit/aktuell" element={<Aktuell />} />
                                        <Route path="/zeit/zukunft" element={<Zukunft />} />
                                        <Route path="/studio" element={<Studio />} />
                                        <Route path="/live" element={<Live />} />
                                        <Route path="/kontakt" element={<Kontakt />} />
                                        <Route path="/datenschutz" element={<Datenschutz />} />
                                        <Route path="/impressum" element={<Impressum />} />
                                        <Route path="*" element={<ErrorPage errorCode="Error Code: 418" errorMessage="I'm a Teapot; #(RFC 2324, RFC 7168)" />} />
                                    </Routes>
                                </Suspense>
                                <Footer />
                            </>
                        )}
                    </Box>
                </Router>
            </ErrorBoundary>
        </ThemeProvider>
    );
}

export default App;

页面在桌面端可正常加载,但在智能手机上始终仅显示Loader加载组件,无法显示Home页面。已尝试替换为极简的Hello World版Home组件测试,也移除了之前嵌入的自定义字体,但问题仍未解决,求排查思路或代码错误分析。


排查思路&代码错误分析

1. 修复CSS语法错误

代码中Box组件的minHeight: '100 vh'存在空格,正确写法应为'100vh'。桌面端浏览器可能容错,但移动端浏览器解析异常可能导致布局阻塞,直接影响组件渲染:

sx={{
  minHeight: '100vh', // 去掉100和vh之间的空格
  // ...其他样式
}}

2. 修正window.load事件的移动端兼容性

移动端浏览器的load事件触发逻辑和桌面端有差异,部分场景下可能不会触发(如缓存、WebView环境)。建议替换为兼容性更好的DOMContentLoaded,同时做兜底处理:

useEffect(() => {
  const minLoadingTime = 1000;
  const startTime = Date.now();

  const finishLoading = () => {
    const elapsedTime = Date.now() - startTime;
    setTimeout(() => setLoading(false), Math.max(0, minLoadingTime - elapsedTime));
  };

  // 页面已就绪则直接执行,否则监听事件
  if (document.readyState === 'complete' || document.readyState === 'interactive') {
    finishLoading();
  } else {
    document.addEventListener('DOMContentLoaded', finishLoading);
    window.addEventListener('load', finishLoading); // 兜底
  }

  return () => {
    document.removeEventListener('DOMContentLoaded', finishLoading);
    window.removeEventListener('load', finishLoading);
  };
}, []);

3. 检查ErrorBoundary的错误捕获

外层的ErrorBoundary可能捕获了移动端特有的错误但未暴露。可以临时修改ErrorBoundary组件,让它在捕获错误时打印控制台日志,或者直接显示错误内容,同时用Chrome远程调试移动端页面查看报错信息。

4. 排查自定义光标资源的影响

移动端浏览器基本不支持自定义光标,若MUSIC_MOUSE资源路径在移动端加载失败,可能阻塞页面渲染。可以临时注释掉cursor属性测试:

// cursor: `url(${MUSIC_MOUSE}) 16 16, auto`,

5. 测试懒加载的兼容性

虽然主流移动端浏览器支持动态import,但仍可尝试临时去掉懒加载,直接导入Home组件验证:

// 替换懒加载为直接导入
import Home from "../Components/Pages/Home";
// 同时可以去掉Suspense包裹,或保留但测试

6. 验证路由模式

移动端可能存在history模式的兼容性问题,可临时切换为HashRouter测试:

import { HashRouter as Router, Route, Routes } from 'react-router-dom';

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 21:50:56