乐闻世界logo
搜索文章和话题

NextJS 如何当路由匹配时设置链接样式?

7 个月前提问
3 个月前修改
浏览次数107

6个答案

1
2
3
4
5
6

在Next.js中,当你希望在路由匹配时改变链接的样式,可以使用 Next.js 提供的 Link 组件与 useRouter 钩子来实现。下面是一个具体的步骤和代码示例:

  1. 导入必要的模块 - 从 next/link 导入 Link 组件,从 next/router 导入 useRouter 钩子。
  2. 使用 useRouter - 在你的组件内部,使用 useRouter 钩子得到当前的路由对象。
  3. 比对路由 - 使用路由对象的 pathname 属性来判断当前路由是否与链接的目标路由匹配。
  4. 设置样式 - 根据路由是否匹配,动态地应用不同的样式类或样式对象到你的链接元素上。

下面是一个简化的代码示例,展示了如何实现这一过程:

jsx
import Link from 'next/link'; import { useRouter } from 'next/router'; export default function NavLink({ href, children }) { // 使用 useRouter 钩子获取当前路由信息 const router = useRouter(); // 检查此链接是否为当前路由,如果是,则设置一个特殊的样式类 const isActive = router.pathname === href; // 根据是否激活来决定样式 const linkStyle = { fontWeight: isActive ? 'bold' : 'normal', color: isActive ? 'green' : 'blue', }; return ( <Link href={href}> <a style={linkStyle}>{children}</a> </Link> ); }

这个 NavLink 组件可以这样使用:

jsx
function NavigationBar() { return ( <nav> <NavLink href="/">Home</NavLink> <NavLink href="/about">About</NavLink> <NavLink href="/contact">Contact</NavLink> </nav> ); }

在这个例子中,当用户导航到与 NavLink href 属性相匹配的路由时,链接的样式将变成粗体和绿色。如果不匹配,链接的样式将是普通字体和蓝色。这样可以很直观地向用户展示他们当前所处的页面。

这只是一个简单的样式设置方法。你也可以根据需要将样式类与元素类一起使用,进一步提升样式的复杂度和灵活性。

2024年6月29日 12:07 回复

A simple solution based on the useRouter hook:

shell
import Link from "next/link"; import { useRouter } from "next/router"; export const MyNav = () => { const router = useRouter(); return ( <ul> <li className={router.pathname == "/" ? "active" : ""}> <Link href="/">home</Link> </li> <li className={router.pathname == "/about" ? "active" : ""}> <Link href="/about">about</Link> </li> </ul> ); };

You could also use router.asPath instead of router.pathname if you want to include the url query parameters. This can be useful if you want to handle anchor tags such as /#about.

2024年6月29日 12:07 回复

First, you need to have a component called Link, with temporary attribute activeClassName

shell
import { useRouter } from 'next/router' import PropTypes from 'prop-types' import Link from 'next/link' import React, { Children } from 'react' const ActiveLink = ({ children, activeClassName, ...props }) => { const { asPath } = useRouter() const child = Children.only(children) const childClassName = child.props.className || '' // pages/index.js will be matched via props.href // pages/about.js will be matched via props.href // pages/[slug].js will be matched via props.as const className = asPath === props.href || asPath === props.as ? `${childClassName} ${activeClassName}`.trim() : childClassName return ( <Link {...props}> {React.cloneElement(child, { className: className || null, })} </Link> ) } ActiveLink.propTypes = { activeClassName: PropTypes.string.isRequired, } export default ActiveLink

Then have a navigation bar with created component Link and css selector :active to differentiate between active and inactive link.

shell
import ActiveLink from './ActiveLink' const Nav = () => ( <nav> <style jsx>{` .nav-link { text-decoration: none; } .active:after { content: ' (current page)'; } `}</style> <ul className="nav"> <li> <ActiveLink activeClassName="active" href="/"> <a className="nav-link">Home</a> </ActiveLink> </li> <li> <ActiveLink activeClassName="active" href="/about"> <a className="nav-link">About</a> </ActiveLink> </li> <li> <ActiveLink activeClassName="active" href="/[slug]" as="/dynamic-route"> <a className="nav-link">Dynamic Route</a> </ActiveLink> </li> </ul> </nav> ) export default Nav

After that, you can implement the navigation bar to your page:

shell
import Nav from '../components/Nav' export default () => ( <div> <Nav /> <p>Hello, I'm the home page</p> </div> )

The key of how does this work is located inside component Link, we compare the value of router.pathname with attribute href from the Link, if the value match the other then put specific className to make the link looks activated.

Reference: here

2024年6月29日 12:07 回复

If you're using Next 13 you can now do the following using the usePathname() hook:

shell
import { usePathname} from 'next/navigation'; export default function Example() { const pathname = usePathname(); return( <div> <a href="/welcome" className={pathname == "/welcome" ? "active" : "" } > </div> ) }
2024年6月29日 12:07 回复

If you want to use an anchor Link try this version of @Rotareti 's code:

shell
import Link from "next/link"; import { useRouter } from "next/router"; export const MyNav = () => { const router = useRouter(); return ( <ul> <li className={router.asPath == "/#about" ? "active" : ""}> <Link href="#about">about</Link> </li> </ul> ); };
2024年6月29日 12:07 回复

Another minimal version which supports as prop:

shell
import Link from "next/link"; import {withRouter} from "next/router"; import {Children} from "react"; import React from "react"; export default withRouter(({router, children, as, href, ...rest}) => ( <Link {...rest} href={href} as={as}> {React.cloneElement(Children.only(children), { className: (router.asPath === href || router.asPath === as) ? `active` : null })} </Link> ));
2024年6月29日 12:07 回复

你的答案