当路由在 Next.js 中处于活动状态时,目标活动链接

IT技术 reactjs react-router next.js
2021-03-28 16:23:02

如何像我们在 React-Router-4 中那样定位 Next.js 中的活动链接?意思是,当它的路由处于活动状态时,给活动链接一个类?

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>
  );
};

如果页面中存在参数,则此解决方案将不起作用!
2021-05-24 16:23:02
但是,如果您路由到诸如 www.example.com/blog/xyz 之类的嵌套链接,则此操作不起作用。链接在嵌套链接中变为非活动状态
2021-05-25 16:23:02
如果您的链接指向像<Link href="/#about">. 你如何使它成为一个活动链接?
2021-05-26 16:23:02
如果你有类组件,你怎么做?
2021-05-28 16:23:02
@gurupalsingh 我认为在这种情况下你可以使用 router.pathname.startsWith("/about") ? "active" : ""
2021-06-08 16:23:02

首先,您需要有一个名为 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,让链接看起来是激活的。

参考:这里

我在哪里创建链接文件?在我的组件文件夹中还是在根文件夹中?有两个名为“Link”的文件不是不好的做法吗?你有一个来自 next/link 和一个名为 link 的组件。
2021-05-29 16:23:02
但是,如果您路由到诸如 www.example.com/blog/xyz 之类的嵌套链接,则此操作不起作用。链接在嵌套链接中变为非活动状态。
2021-05-29 16:23:02
但它不适用于嵌套路由。例如,它适用于“/settings”,但不适用于“/settings/locations”。我们如何为多个路由启用与 Active 相同的文本?
2021-06-05 16:23:02
@larryburns 您的组件文件夹,恕我直言,只要清楚您指向哪个链接就行,但您也可以将链接组件重命名为其他名称。这取决于您,您可以在索引文件中重新定义它,或者只是重命名组件,使其与下一个/链接组件完全不同
2021-06-12 16:23:02
请参阅我的答案以获取基于此代码的解决方案,但要注意嵌套链接和 url 参数
2021-06-20 16:23:02

另一个支持asprop 的最小版本

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>
));
router.asPath只在开发中工作(真的不知道为什么),我换成了router.pathname === href || router.pathname === as在生产中工作。
2021-05-25 16:23:02
我喜欢这个答案,如果你想保留孩子的课程并只是追加,请使用:className: router.asPath === href || router.asPath === as ? ${children.props.className} active:children.props.className
2021-06-03 16:23:02

如果您想使用锚链接,请尝试使用此版本的 @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>
  )
}

请注意,除非必要,否则我不会克隆孩子。