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

时间:2018-11-12 12:31:09

标签: reactjs react-router next.js

如何像在React-Router-4中那样将Next.js中的活动链接作为目标? 意思是,在活动链接的路由处于活动状态时为其指定一个类吗?

8 个答案:

答案 0 :(得分:5)

另一个支持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>
));

答案 1 :(得分:3)

首先,您需要有一个名为Link的组件,其临时属性为activeClassName

import { withRouter } from 'next/router'
import Link from 'next/link'
import React, { Children } from 'react'

const ActiveLink = ({ router, children, ...props }) => {
  const child = Children.only(children)

  let className = child.props.className || null
  if (router.pathname === props.href && props.activeClassName) {
    className = `${className !== null ? className : ''} ${props.activeClassName}`.trim()
  }

  delete props.activeClassName

  return <Link {...props}>{React.cloneElement(child, { className })}</Link>
}

export default withRouter(ActiveLink)

然后有一个导航栏,该导航栏具有创建的组件Link和CSS选择器:active,以区分活动链接和非活动链接。

import Link from './Link'

export default () => (
  <nav>
    <style jsx>{`
      .active:after {
        content: ' (current page)';
      }
      .nav-link {
        text-decoration: none;
        padding: 10px;
        display: block;
      }
    `}</style>

    <ul>
      <li>
        <Link activeClassName='active' href='/'>
          <a className='nav-link home-link'>Home</a>
        </Link>
      </li>
      <li>
        <Link activeClassName='active' href='/about'>
          <a className='nav-link'>About</a>
        </Link>
      </li>
    </ul>
  </nav>
)

之后,您可以在页面上实现导航栏:

import Nav from '../components/Nav'

export default () => (
  <div>
    <Nav />
    <p>Hello, I'm the home page</p>
  </div>
)

此工作原理的关键位于组件Link内,我们将router.pathname的值与Link中的属性href进行比较,如果该值与另一个匹配,则放置特定的className以使链接看起来已激活。

参考:here

答案 2 :(得分:1)

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

打字稿版本:

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

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

答案 5 :(得分:0)

这里有一个解决方案,如果存在 URL 参数并检查子页面是否处于活动状态,则该解决方案也有效。基于 Darryl RN 和 Saman Mohamadi 的回答

它可以替代 NextJS 链接组件,并在路由或子页面的路由处于活动状态时添加“active”和“active-sub”类。

创建一个名为 Link.js 或任何你喜欢的文件:

import { withRouter } from "next/router";
import Link from "next/link";
import React, { Children } from "react";

export default withRouter(({ router, children, as, href, activeClassName, activeSubClassName, ...rest }) => {
  const child = Children.only(children);
  const childClassName = child.props.className || "";
  // remove URL parameters
  const sanitizedPath = router.asPath.split("#")[0].split("?")[0];
  // activeClassName and activeSubClassName are optional and default to "active" and "active-sub"
  const activeClass = activeClassName || "active";
  const activeSubClass = activeSubClassName || "active-sub";
  // check if the link or a sub-page is active and return the according class name
  const activityClassName = sanitizedPath === href || sanitizedPath === as ? activeClass : sanitizedPath.startsWith(href + "/") || sanitizedPath.startsWith(as + "/") ? activeSubClass : "";
  // combine the child class names with the activity class name
  const className = `${childClassName} ${activityClassName}`.trim();
  return (
    <Link href={href} as={as} {...rest}>
      {React.cloneElement(child, {
        className: className || null,
      })}
    </Link>
  );
});

通过

将其导入到您的文件中
import Link from "./Link.js";

或者任何你喜欢的名字

import ActiveLink from "./Link.js";

并像使用 NextJS“链接”组件(下一个/链接)一样使用它:

<Link href="/home">
  <a className="link-classname">Home</a>
</Link>

它会默认为类名“active”和“active-sub”,但您可以设置自定义类名:

<Link href="/home" activeClassName="my-active-classname" activeSubClassName="another-classname">
  <a className="link-classname">Home</a>
</Link>

如果您不需要其中一个活动类,请在字符串中放置一个空格:

<Link href="/home" activeSubClassName=" ">
  <a className="link-classname">Home</a>
</Link>

答案 6 :(得分:0)

只需在其中放置一个标签...

<Link href={href}>
  <a className='text-red-400 active:text-red-800'>{children}</a>
</Link>

答案 7 :(得分:0)

这是我的解决方案。我标记 hrefasPath 道具,然后循环匹配它们。

您可以选择精确链接(默认)

<ActiveLink href='/events'>
    <a href='/page'>Page</a>
</ActiveLink>

或带有 fuzzy 属性的模糊链接(匹配 /events)

<ActiveLink fuzzy href='/events/id'>
    <a href='/events/id'>Event</a>
</ActiveLink>

这是组件

import React from 'react';
import NextLink from 'next/link';
import { useRouter } from 'next/router';

const ActiveLink = ({ fuzzy = false, href, children }) => {
const router = useRouter();
let className = children.props.className || '';

const hrefTokens = href.substr(1).split('/');
const pathTokens = router.asPath.substr(1).split('/');

let matched = false;
for (let i = 0; i < hrefTokens.length; i++) {
    if (hrefTokens[i] === pathTokens[i]) {
    matched = true;
    break;
    }
 }

 if ((!fuzzy && router.asPath === href) || (fuzzy && matched)) {
    className = `${className} active`;
  }

  return (
    <NextLink href={href}>
      {React.cloneElement(children, { className })}
    </NextLink>
  );
};

export default ActiveLink;