增加页面切换进度条
This commit is contained in:
@@ -2,6 +2,43 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* NProgress 进度条样式 */
|
||||
#nprogress {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#nprogress .bar {
|
||||
background: #3b82f6;
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
box-shadow: 0 0 10px rgba(59, 130, 246, 0.8), 0 0 5px rgba(59, 130, 246, 0.6);
|
||||
}
|
||||
|
||||
#nprogress .peg {
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
width: 100px;
|
||||
height: 100%;
|
||||
box-shadow: 0 0 10px rgba(59, 130, 246, 0.8), 0 0 5px rgba(59, 130, 246, 0.6);
|
||||
opacity: 1.0;
|
||||
transform: rotate(3deg) translate(0px, -4px);
|
||||
}
|
||||
|
||||
/* 暗色模式下的进度条样式 */
|
||||
.dark #nprogress .bar {
|
||||
background: #60a5fa;
|
||||
box-shadow: 0 0 10px rgba(96, 165, 250, 0.8), 0 0 5px rgba(96, 165, 250, 0.6);
|
||||
}
|
||||
|
||||
.dark #nprogress .peg {
|
||||
box-shadow: 0 0 10px rgba(96, 165, 250, 0.8), 0 0 5px rgba(96, 165, 250, 0.6);
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.scrollbar-hide {
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
|
||||
@@ -16,6 +16,7 @@ import { DownloadProvider } from '../contexts/DownloadContext';
|
||||
import { DownloadBubble } from '../components/DownloadBubble';
|
||||
import { DownloadPanel } from '../components/DownloadPanel';
|
||||
import { DanmakuCacheCleanup } from '../components/DanmakuCacheCleanup';
|
||||
import TopProgressBar from '../components/TopProgressBar';
|
||||
|
||||
const inter = Inter({ subsets: ['latin'] });
|
||||
export const dynamic = 'force-dynamic';
|
||||
@@ -194,6 +195,7 @@ export default async function RootLayout({
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
<TopProgressBar />
|
||||
<SiteProvider siteName={siteName} announcement={announcement} tmdbApiKey={tmdbApiKey}>
|
||||
<WatchRoomProvider>
|
||||
<DownloadProvider>
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { usePathname, useSearchParams, useRouter } from 'next/navigation';
|
||||
import NProgress from 'nprogress';
|
||||
|
||||
// 创建全局钩子来拦截 router
|
||||
let globalRouterRef: any = null;
|
||||
|
||||
export default function TopProgressBar() {
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
const router = useRouter();
|
||||
const isNavigatingRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
// 配置 NProgress
|
||||
NProgress.configure({
|
||||
showSpinner: false,
|
||||
trickleSpeed: 200,
|
||||
minimum: 0.08,
|
||||
easing: 'ease',
|
||||
speed: 200,
|
||||
});
|
||||
|
||||
// 保存原始的 router 方法
|
||||
globalRouterRef = router;
|
||||
const originalPush = router.push;
|
||||
const originalReplace = router.replace;
|
||||
const originalBack = router.back;
|
||||
const originalForward = router.forward;
|
||||
|
||||
// 拦截 router.push
|
||||
router.push = function (...args: any[]) {
|
||||
isNavigatingRef.current = true;
|
||||
NProgress.start();
|
||||
return originalPush.apply(this, args);
|
||||
};
|
||||
|
||||
// 拦截 router.replace
|
||||
router.replace = function (...args: any[]) {
|
||||
isNavigatingRef.current = true;
|
||||
NProgress.start();
|
||||
return originalReplace.apply(this, args);
|
||||
};
|
||||
|
||||
// 拦截 router.back
|
||||
router.back = function () {
|
||||
isNavigatingRef.current = true;
|
||||
NProgress.start();
|
||||
return originalBack.apply(this);
|
||||
};
|
||||
|
||||
// 拦截 router.forward
|
||||
router.forward = function () {
|
||||
isNavigatingRef.current = true;
|
||||
NProgress.start();
|
||||
return originalForward.apply(this);
|
||||
};
|
||||
|
||||
// 监听所有链接点击事件
|
||||
const handleAnchorClick = (event: MouseEvent) => {
|
||||
const target = event.target as HTMLElement;
|
||||
const anchor = target.closest('a');
|
||||
|
||||
if (anchor && anchor.href) {
|
||||
const currentUrl = window.location.href;
|
||||
const targetUrl = anchor.href;
|
||||
|
||||
if (targetUrl !== currentUrl && !anchor.target && !anchor.download) {
|
||||
const currentOrigin = window.location.origin;
|
||||
try {
|
||||
const targetOrigin = new URL(targetUrl, currentOrigin).origin;
|
||||
if (currentOrigin === targetOrigin) {
|
||||
isNavigatingRef.current = true;
|
||||
NProgress.start();
|
||||
}
|
||||
} catch (e) {
|
||||
// URL 解析失败,忽略
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 监听浏览器前进后退按钮
|
||||
const handlePopState = () => {
|
||||
isNavigatingRef.current = true;
|
||||
NProgress.start();
|
||||
};
|
||||
|
||||
document.addEventListener('click', handleAnchorClick, true);
|
||||
window.addEventListener('popstate', handlePopState);
|
||||
|
||||
return () => {
|
||||
// 恢复原始方法
|
||||
if (globalRouterRef) {
|
||||
globalRouterRef.push = originalPush;
|
||||
globalRouterRef.replace = originalReplace;
|
||||
globalRouterRef.back = originalBack;
|
||||
globalRouterRef.forward = originalForward;
|
||||
}
|
||||
|
||||
document.removeEventListener('click', handleAnchorClick, true);
|
||||
window.removeEventListener('popstate', handlePopState);
|
||||
};
|
||||
}, [router]);
|
||||
|
||||
useEffect(() => {
|
||||
// 页面路径变化时,表示页面已加载完成,结束进度条
|
||||
if (isNavigatingRef.current) {
|
||||
NProgress.done();
|
||||
isNavigatingRef.current = false;
|
||||
}
|
||||
}, [pathname, searchParams]);
|
||||
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user