107 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useEffect, useState } from 'react';
import { useLocation } from 'umi';
import SkeletonLoading from '../SkeletonLoading';
import { routePreloader } from '@/utils/routePreloader';
interface SmartLoadingProps {
fallback?: React.ReactNode;
enablePreload?: boolean;
}
/**
* 智能加载组件
* 根据路由类型自动选择合适的骨架屏,并支持路由预加载
*/
const SmartLoading: React.FC<SmartLoadingProps> = ({
fallback,
enablePreload = true
}) => {
const [loadingType, setLoadingType] = useState<'page' | 'table' | 'form' | 'card'>('page');
const [shouldShow, setShouldShow] = useState(false);
const [location, setLocation] = useState<any>(null);
// 安全获取location避免在路由未准备好时出错
try {
const currentLocation = useLocation();
if (!location) {
setLocation(currentLocation);
}
} catch (error) {
// 如果useLocation失败使用window.location作为fallback
if (!location && typeof window !== 'undefined') {
setLocation({ pathname: window.location.pathname });
}
}
useEffect(() => {
// 对于页面切换,立即显示骨架屏,但对于初始加载延迟显示
const isInitialLoad = !location?.pathname || location.pathname === '/';
if (isInitialLoad) {
// 初始加载时延迟显示,避免刷新时闪烁
const timer = setTimeout(() => {
setShouldShow(true);
}, 200);
return () => clearTimeout(timer);
} else {
// 页面切换时立即显示,保持骨架屏效果
setShouldShow(true);
}
}, [location?.pathname]);
useEffect(() => {
if (!location?.pathname) return;
// 根据路径判断页面类型,选择合适的骨架屏
const path = location.pathname;
if (path.includes('list') || path.includes('table')) {
setLoadingType('table');
} else if (path.includes('form') || path.includes('edit') || path.includes('add')) {
setLoadingType('form');
} else if (path.includes('card') || path.includes('dashboard')) {
setLoadingType('card');
} else {
setLoadingType('page');
}
// 预加载相关路由(降低优先级,避免影响主流程)
if (enablePreload) {
setTimeout(() => {
routePreloader.preloadBasedOnUserBehavior(path);
}, 500);
}
}, [location?.pathname, enablePreload]);
// 如果提供了自定义fallback使用它
if (fallback) {
return <>{fallback}</>;
}
// 延迟显示,避免闪烁
if (!shouldShow) {
return null;
}
// 根据页面类型返回对应的骨架屏
return <SkeletonLoading type={loadingType} rows={getRowsByType(loadingType)} />;
};
/**
* 根据加载类型获取合适的行数
*/
function getRowsByType(type: string): number {
switch (type) {
case 'table':
return 8; // 表格通常显示更多行
case 'form':
return 5; // 表单通常5-6个字段
case 'card':
return 6; // 卡片网格通常6个
case 'page':
default:
return 4; // 默认4行
}
}
export default SmartLoading;