Skip to content

NextJS 打开新标签页链接

问题描述

在 NextJS 中,当你尝试使用 <Link> 组件打开外部链接(如 Twitter)时,可能会遇到 ESLint 警告:

bash
ESLint: The href attribute is required for an anchor to be keyboard accessible. Provide a valid, navigable address as the href value.

这个问题通常发生在 NextJS 的不同版本中,特别是当开发者尝试在 <Link> 组件中嵌套 <a> 标签时。

解决方案

根据 NextJS 版本的不同,有多种方法可以正确地在新的标签页中打开链接。

方法一:直接使用 <a> 标签(推荐用于外部链接)

对于外部链接,最简单直接的方法是使用原生 HTML 的 <a> 标签:

jsx
<a 
  href="https://twitter.com/" 
  target="_blank" 
  rel="noopener noreferrer"
>
  <div className={`${dark ? styles.iconTwitterWhite : styles.iconTwitter} mr-3`} />
</a>

为什么使用 rel="noopener noreferrer"

  • noopener:防止新打开的页面通过 window.opener 访问原页面
  • noreferrer:隐藏引用来源信息,增强安全性

从 NextJS 13 开始,<Link> 组件直接渲染为 <a> 标签,无需嵌套额外的 <a> 元素:

jsx
import Link from 'next/link';

<Link
  href="https://twitter.com/"
  target="_blank"
  rel="noopener noreferrer"
  className="your-custom-class"
>
  <div className={`${dark ? styles.iconTwitterWhite : styles.iconTwitter} mr-3`} />
</Link>

方法三:NextJS 12 及之前版本

对于较旧版本的 NextJS,需要使用 passHreflegacyBehavior 属性:

jsx
<Link 
  href="https://twitter.com/" 
  passHref 
  legacyBehavior
>
  <a 
    target="_blank" 
    rel="noopener noreferrer"
  >
    <div className={`${dark ? styles.iconTwitterWhite : styles.iconTwitter} mr-3`} />
  </a>
</Link>

方法四:使用编程式导航

如果需要更复杂的逻辑控制,可以使用 NextJS 的路由器:

jsx
import { useRouter } from "next/router";

export default function App() {
  const openInNewTab = (url) => {
    const newWindow = window.open(url, '_blank', 'noopener,noreferrer');
    if (newWindow) newWindow.opener = null;
  };
  
  return (
    <div onClick={() => openInNewTab("https://twitter.com/")}>
      <div className={`${dark ? styles.iconTwitterWhite : styles.iconTwitter} mr-3`} />
    </div>
  );
}

版本兼容性指南

jsx
// 直接使用 Link 组件
<Link
  href="/menu"
  target="_blank"
  rel="noopener noreferrer"
>
  显示菜单
</Link>
jsx
// Link 组件已自动处理 a 标签
<Link
  href={siteConfig.links.twitter}
  target="_blank"
  rel="noreferrer"
  className={buttonVariants()}
>
  Twitter
</Link>
jsx
// 需要使用 passHref 和 legacyBehavior
<Link href="/about" passHref legacyBehavior>
  <a target="_blank" rel="noopener noreferrer">
    关于我们
  </a>
</Link>

最佳实践

  1. 外部链接使用 <a> 标签:对于指向其他网站的链接,直接使用 <a> 标签更合适
  2. 内部链接使用 <Link> 组件:对于应用内导航,使用 <Link> 以获得更好的性能
  3. 始终添加安全属性:使用 rel="noopener noreferrer" 防止安全漏洞
  4. 考虑可访问性:确保所有链接都有有意义的文本或适当的 ARIA 标签

常见问题

避免 hydration 错误

在较新版本的 NextJS 中,不要在 <Link> 组件内嵌套 <a> 标签,这会导致 hydration 错误。

不要忽略 ESLint 警告

ESLint 的 accessibility 警告是为了确保你的网站对所有用户都可访问,不应忽略。

配置管理建议

对于大型项目,建议将链接配置集中管理:

jsx
// config/site.js
export const siteConfig = {
  links: {
    twitter: "https://twitter.com/yourhandle",
    github: "https://github.com/yourusername",
    // 其他链接...
  },
};

// 在组件中使用
<Link
  href={siteConfig.links.twitter}
  target="_blank"
  rel="noopener noreferrer"
>
  Twitter
</Link>

总结

在 NextJS 中打开新标签页链接的方法取决于你的 NextJS 版本和链接类型。对于外部链接,推荐直接使用 <a> 标签;对于内部链接,使用适当版本的 <Link> 组件。无论使用哪种方法,都不要忘记添加必要的安全属性以确保用户体验和网站安全。