如何像我们在 React-Router-4 中那样定位 Next.js 中的活动链接?意思是,当它的路由处于活动状态时,给活动链接一个类?
当路由在 Next.js 中处于活动状态时,目标活动链接
IT技术
reactjs
react-router
next.js
2021-03-28 16:23:02
6个回答
基于useRouter
钩子的简单解决方案:
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>
);
};
首先,您需要有一个名为 Link 的组件,具有临时属性 activeClassName
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
然后有一个带有创建的组件链接和 css 选择器的导航栏:active
来区分活动和非活动链接。
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
之后,您可以将导航栏实现到您的页面:
import Nav from '../components/Nav'
export default () => (
<div>
<Nav />
<p>Hello, I'm the home page</p>
</div>
)
这个工作的关键是在组件Link里面,我们比较一下Link中router.pathname
的属性href
值,如果匹配到其他的就放具体的className,让链接看起来是激活的。
参考:这里
另一个支持as
prop 的最小版本:
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>
));
如果您想使用锚链接,请尝试使用此版本的 @Rotareti 代码:
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>
);
}`;
typescript版本:
import React from 'react'
import Link, { LinkProps } from 'next/link'
import { useRouter } from 'next/router'
export interface NavLinkProps extends LinkProps {
children: React.ReactElement
}
export function NavLink({ children, href, ...props }: NavLinkProps) {
const router = useRouter()
return (
<Link href={href} {...props}>
{router.pathname === href ? React.cloneElement(children, { 'data-active': true }) : children}
</Link>
)
}
请注意,除非必要,否则我不会克隆孩子。