尝试修复导航切换阻塞
This commit is contained in:
17
.vscode/launch.json
vendored
Normal file
17
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch Program",
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**"
|
||||||
|
],
|
||||||
|
"program": "${workspaceFolder}/start"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
import { Cat, Clover, Film, Home, Radio, Star, Tv } from 'lucide-react';
|
import { Cat, Clover, Film, Home, Radio, Star, Tv } from 'lucide-react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { usePathname } from 'next/navigation';
|
import { usePathname, useSearchParams } from 'next/navigation';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
interface MobileBottomNavProps {
|
interface MobileBottomNavProps {
|
||||||
@@ -16,9 +16,14 @@ interface MobileBottomNavProps {
|
|||||||
|
|
||||||
const MobileBottomNav = ({ activePath }: MobileBottomNavProps) => {
|
const MobileBottomNav = ({ activePath }: MobileBottomNavProps) => {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
|
const searchParams = useSearchParams();
|
||||||
|
|
||||||
// 当前激活路径:优先使用传入的 activePath,否则回退到浏览器地址
|
// 直接使用当前路由状态,确保立即响应路由变化
|
||||||
const currentActive = activePath ?? pathname;
|
const getCurrentFullPath = () => {
|
||||||
|
const queryString = searchParams.toString();
|
||||||
|
return queryString ? `${pathname}?${queryString}` : pathname;
|
||||||
|
};
|
||||||
|
const currentActive = activePath ?? getCurrentFullPath();
|
||||||
|
|
||||||
const [navItems, setNavItems] = useState([
|
const [navItems, setNavItems] = useState([
|
||||||
{ icon: Home, label: '首页', href: '/' },
|
{ icon: Home, label: '首页', href: '/' },
|
||||||
@@ -98,6 +103,7 @@ const MobileBottomNav = ({ activePath }: MobileBottomNavProps) => {
|
|||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
href={item.href}
|
href={item.href}
|
||||||
|
prefetch={false}
|
||||||
className='flex flex-col items-center justify-center w-full h-14 gap-1 text-xs'
|
className='flex flex-col items-center justify-center w-full h-14 gap-1 text-xs'
|
||||||
>
|
>
|
||||||
<item.icon
|
<item.icon
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ const MobileHeader = ({ showBackButton = false }: MobileHeaderProps) => {
|
|||||||
<div className='flex items-center gap-2'>
|
<div className='flex items-center gap-2'>
|
||||||
<Link
|
<Link
|
||||||
href='/search'
|
href='/search'
|
||||||
|
prefetch={false}
|
||||||
className='w-10 h-10 p-2 rounded-full flex items-center justify-center text-gray-600 hover:bg-gray-200/50 dark:text-gray-300 dark:hover:bg-gray-700/50 transition-colors'
|
className='w-10 h-10 p-2 rounded-full flex items-center justify-center text-gray-600 hover:bg-gray-200/50 dark:text-gray-300 dark:hover:bg-gray-700/50 transition-colors'
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@@ -51,6 +52,7 @@ const MobileHeader = ({ showBackButton = false }: MobileHeaderProps) => {
|
|||||||
<div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'>
|
<div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'>
|
||||||
<Link
|
<Link
|
||||||
href='/'
|
href='/'
|
||||||
|
prefetch={false}
|
||||||
className='text-2xl font-bold text-green-600 tracking-tight hover:opacity-80 transition-opacity'
|
className='text-2xl font-bold text-green-600 tracking-tight hover:opacity-80 transition-opacity'
|
||||||
>
|
>
|
||||||
{siteName}
|
{siteName}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
import { Cat, Clover, Film, Home, Menu, Radio, Search, Star, Tv } from 'lucide-react';
|
import { Cat, Clover, Film, Home, Menu, Radio, Search, Star, Tv } from 'lucide-react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
import { usePathname, useSearchParams } from 'next/navigation';
|
||||||
import {
|
import {
|
||||||
createContext,
|
createContext,
|
||||||
useCallback,
|
useCallback,
|
||||||
@@ -54,7 +54,6 @@ declare global {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Sidebar = ({ onToggle, activePath = '/' }: SidebarProps) => {
|
const Sidebar = ({ onToggle, activePath = '/' }: SidebarProps) => {
|
||||||
const router = useRouter();
|
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
// 若同一次 SPA 会话中已经读取过折叠状态,则直接复用,避免闪烁
|
// 若同一次 SPA 会话中已经读取过折叠状态,则直接复用,避免闪烁
|
||||||
@@ -92,19 +91,14 @@ const Sidebar = ({ onToggle, activePath = '/' }: SidebarProps) => {
|
|||||||
const [active, setActive] = useState(activePath);
|
const [active, setActive] = useState(activePath);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 优先使用传入的 activePath
|
// 立即根据当前路径更新状态,不等待页面加载
|
||||||
if (activePath) {
|
const getCurrentFullPath = () => {
|
||||||
setActive(activePath);
|
const queryString = searchParams.toString();
|
||||||
} else {
|
return queryString ? `${pathname}?${queryString}` : pathname;
|
||||||
// 否则使用当前路径
|
};
|
||||||
const getCurrentFullPath = () => {
|
const fullPath = getCurrentFullPath();
|
||||||
const queryString = searchParams.toString();
|
setActive(fullPath);
|
||||||
return queryString ? `${pathname}?${queryString}` : pathname;
|
}, [pathname, searchParams]);
|
||||||
};
|
|
||||||
const fullPath = getCurrentFullPath();
|
|
||||||
setActive(fullPath);
|
|
||||||
}
|
|
||||||
}, [activePath, pathname, searchParams]);
|
|
||||||
|
|
||||||
const handleToggle = useCallback(() => {
|
const handleToggle = useCallback(() => {
|
||||||
const newState = !isCollapsed;
|
const newState = !isCollapsed;
|
||||||
@@ -116,10 +110,6 @@ const Sidebar = ({ onToggle, activePath = '/' }: SidebarProps) => {
|
|||||||
onToggle?.(newState);
|
onToggle?.(newState);
|
||||||
}, [isCollapsed, onToggle]);
|
}, [isCollapsed, onToggle]);
|
||||||
|
|
||||||
const handleSearchClick = useCallback(() => {
|
|
||||||
router.push('/search');
|
|
||||||
}, [router]);
|
|
||||||
|
|
||||||
const contextValue = {
|
const contextValue = {
|
||||||
isCollapsed,
|
isCollapsed,
|
||||||
};
|
};
|
||||||
@@ -203,7 +193,11 @@ const Sidebar = ({ onToggle, activePath = '/' }: SidebarProps) => {
|
|||||||
<nav className='px-2 mt-4 space-y-1'>
|
<nav className='px-2 mt-4 space-y-1'>
|
||||||
<Link
|
<Link
|
||||||
href='/'
|
href='/'
|
||||||
onClick={() => setActive('/')}
|
prefetch={false}
|
||||||
|
onClick={(e) => {
|
||||||
|
// 确保点击事件立即生效,不被其他状态更新阻塞
|
||||||
|
e.currentTarget.blur();
|
||||||
|
}}
|
||||||
data-active={active === '/'}
|
data-active={active === '/'}
|
||||||
className={`group flex items-center rounded-lg px-2 py-2 pl-4 text-gray-700 hover:bg-gray-100/30 hover:text-green-600 data-[active=true]:bg-green-500/20 data-[active=true]:text-green-700 font-medium transition-colors duration-200 min-h-[40px] dark:text-gray-300 dark:hover:text-green-400 dark:data-[active=true]:bg-green-500/10 dark:data-[active=true]:text-green-400 ${isCollapsed ? 'w-full max-w-none mx-0' : 'mx-0'
|
className={`group flex items-center rounded-lg px-2 py-2 pl-4 text-gray-700 hover:bg-gray-100/30 hover:text-green-600 data-[active=true]:bg-green-500/20 data-[active=true]:text-green-700 font-medium transition-colors duration-200 min-h-[40px] dark:text-gray-300 dark:hover:text-green-400 dark:data-[active=true]:bg-green-500/10 dark:data-[active=true]:text-green-400 ${isCollapsed ? 'w-full max-w-none mx-0' : 'mx-0'
|
||||||
} gap-3 justify-start`}
|
} gap-3 justify-start`}
|
||||||
@@ -219,11 +213,6 @@ const Sidebar = ({ onToggle, activePath = '/' }: SidebarProps) => {
|
|||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
href='/search'
|
href='/search'
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
handleSearchClick();
|
|
||||||
setActive('/search');
|
|
||||||
}}
|
|
||||||
data-active={active === '/search'}
|
data-active={active === '/search'}
|
||||||
className={`group flex items-center rounded-lg px-2 py-2 pl-4 text-gray-700 hover:bg-gray-100/30 hover:text-green-600 data-[active=true]:bg-green-500/20 data-[active=true]:text-green-700 font-medium transition-colors duration-200 min-h-[40px] dark:text-gray-300 dark:hover:text-green-400 dark:data-[active=true]:bg-green-500/10 dark:data-[active=true]:text-green-400 ${isCollapsed ? 'w-full max-w-none mx-0' : 'mx-0'
|
className={`group flex items-center rounded-lg px-2 py-2 pl-4 text-gray-700 hover:bg-gray-100/30 hover:text-green-600 data-[active=true]:bg-green-500/20 data-[active=true]:text-green-700 font-medium transition-colors duration-200 min-h-[40px] dark:text-gray-300 dark:hover:text-green-400 dark:data-[active=true]:bg-green-500/10 dark:data-[active=true]:text-green-400 ${isCollapsed ? 'w-full max-w-none mx-0' : 'mx-0'
|
||||||
} gap-3 justify-start`}
|
} gap-3 justify-start`}
|
||||||
@@ -259,7 +248,6 @@ const Sidebar = ({ onToggle, activePath = '/' }: SidebarProps) => {
|
|||||||
<Link
|
<Link
|
||||||
key={item.label}
|
key={item.label}
|
||||||
href={item.href}
|
href={item.href}
|
||||||
onClick={() => setActive(item.href)}
|
|
||||||
data-active={isActive}
|
data-active={isActive}
|
||||||
className={`group flex items-center rounded-lg px-2 py-2 pl-4 text-sm text-gray-700 hover:bg-gray-100/30 hover:text-green-600 data-[active=true]:bg-green-500/20 data-[active=true]:text-green-700 transition-colors duration-200 min-h-[40px] dark:text-gray-300 dark:hover:text-green-400 dark:data-[active=true]:bg-green-500/10 dark:data-[active=true]:text-green-400 ${isCollapsed ? 'w-full max-w-none mx-0' : 'mx-0'
|
className={`group flex items-center rounded-lg px-2 py-2 pl-4 text-sm text-gray-700 hover:bg-gray-100/30 hover:text-green-600 data-[active=true]:bg-green-500/20 data-[active=true]:text-green-700 transition-colors duration-200 min-h-[40px] dark:text-gray-300 dark:hover:text-green-400 dark:data-[active=true]:bg-green-500/10 dark:data-[active=true]:text-green-400 ${isCollapsed ? 'w-full max-w-none mx-0' : 'mx-0'
|
||||||
} gap-3 justify-start`}
|
} gap-3 justify-start`}
|
||||||
|
|||||||
Reference in New Issue
Block a user