在Nobelium的Navbar适配手机端

碎碎念话说貌似过多的页面在navbar的话 手机端貌似不会太好浏览 于是有了这次计划 image.png image.png 比原来的看起来顺眼了一些！教程将原来的 components/Header.js 修改为 import { forwardRef, useCallback, useEffect, useRef, useState } from 'react' import Link from 'next/link' import Image from 'next/image' import { useConfig } from '@/lib/config' import { useLocale } from '@/lib/locale' import useTheme from '@/lib/theme' const NavBar = () => { const BLOG = useConfig() const locale = useLocale() const links = [ { id: 0, name: locale.NAV.INDEX, to: BLOG.path || '/', show: true }, { id: 1, name: locale.NAV.ABOUT, to: '/about', show: BLOG.showAbout }, { id: 2, name: locale.NAV.RSS, to: '/feed', show: true, external: true }, { id: 3, name: locale.NAV.SEARCH, to: '/search', show: true } ] return (

{links.map( link => link.show && (
{link.name}
) )}

) } export default function Header ({ navBarTitle, fullWidth }) { const BLOG = useConfig() const { dark } = useTheme() // Favicon const resolveFavicon = fallback => !fallback && dark ? '/favicon.png' : '/favicon.png' const [favicon, _setFavicon] = useState(resolveFavicon()) const setFavicon = fallback => _setFavicon(resolveFavicon(fallback)) useEffect( () => setFavicon(), // eslint-disable-next-line react-hooks/exhaustive-deps [dark] ) const useSticky = !BLOG.autoCollapsedNavBar const navRef = useRef(/** @type {HTMLDivElement} */ undefined) const sentinelRef = useRef(/** @type {HTMLDivElement} */ undefined) const handler = useCallback(([entry]) => { if (useSticky && navRef.current) { navRef.current?.classList.toggle('sticky-nav-full', !entry.isIntersecting) } else { navRef.current?.classList.add('remove-sticky') } }, [useSticky]) useEffect(() => { const sentinelEl = sentinelRef.current const observer = new window.IntersectionObserver(handler) observer.observe(sentinelEl) return () => { sentinelEl && observer.unobserve(sentinelEl) } }, [handler, sentinelRef]) const titleRef = useRef(/** @type {HTMLParagraphElement} */ undefined) function handleClickHeader (/** @type {MouseEvent} */ ev) { if (![navRef.current, titleRef.current].includes(ev.target)) return window.scrollTo({ top: 0, behavior: 'smooth' }) } // 新增：移动端菜单控制 const [isMobileMenuOpen, setMobileMenuOpen] = useState(false) const locale = useLocale() const links = [ { id: 0, name: locale.NAV.INDEX, to: BLOG.path || '/', show: true }, { id: 1, name: locale.NAV.ABOUT, to: '/about', show: BLOG.showAbout }, { id: 2, name: locale.NAV.RSS, to: '/feed', show: true, external: true }, { id: 3, name: locale.NAV.SEARCH, to: '/search', show: true } ] // 动态检测 html 的 class 是否包含 dark const [isDarkMode, setIsDarkMode] = useState(false) useEffect(() => { const checkDark = () => { setIsDarkMode(document.documentElement.classList.contains('dark')) } checkDark() const observer = new MutationObserver(checkDark) observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] }) return () => observer.disconnect() }, []) return ( <>

{/* 移动端左侧logo+右侧汉堡按钮，桌面端不显示 */}
setFavicon(true)} />

{ e.stopPropagation() setMobileMenuOpen(true) }} >
{/* 桌面端logo+标题+导航 */}
setFavicon(true)} />
{/* 桌面端导航 */}

{/* 移动端全屏菜单 */} {isMobileMenuOpen && (

setMobileMenuOpen(false)}> setMobileMenuOpen(false)} >

{links.filter(link => link.show).map(link => ( setMobileMenuOpen(false)} > {link.name} ))}

)} ) } const HeaderName = forwardRef(function HeaderName ({ siteTitle, siteDescription, postTitle, onClick }, ref) { return (
{postTitle && {postTitle}} {siteTitle} , {siteDescription}
) }) ⚠️ 我之前修改过默认favicon的地址 请你注意（未引用默认config的配置哦！）