React SPA 中的锚点或按钮?
Posted
技术标签:
【中文标题】React SPA 中的锚点或按钮?【英文标题】:Anchor or Button in React SPA? 【发布时间】:2020-08-07 07:00:25 【问题描述】:假设页面上有一段文本(无论其样式是“传统”链接还是按钮),单击该文本会导致带有新页面/URL 的新页面。但是导航是以编程方式发生的(例如,通过 react-router
使用 History Web API)而不是硬 HTTP 刷新。
在这种情况下,它应该是带有href
属性的传统锚链接,例如#
还是一个按钮?
选项 1:
<a href="#" onClick=navigateToNextPage>Link</a>
缺点是你有一个垃圾href
属性。您可以删除它,但它不在选项卡顺序中并且没有获得默认链接样式(尽管这些可以通过一次性样式来克服)。此外,如果您复制链接,它将复制为 #
,这是不正确的,并且屏幕阅读器会错误地解释。
选项 2:
<button onClick=navigateToNextPage>Link</a>
这里的缺点是,如果您希望它看起来像传统链接,则需要应用自定义样式。在我看来,在某些方面它确实像一个传统的链接。但这对于屏幕阅读器来说会更好。
【问题讨论】:
使用history.push()
或 <Link to='' >Link</Link>
。该链接将转换为<a>
,但不会执行“硬刷新:
@Enchew 现在我正在使用history.push()
,但是在href
属性的锚标记中添加什么?现在它也不是很容易访问。
我的意思是在按钮上使用history.push()
,但是如果你想要标签,使用'react-router-dom'中的<Link>
组件,而不是纯
@Enchew 是否应该将按钮用于页面/URL 导航?
有时需要它们——例如,如果你想执行一个 ajax 调用然后重定向用户,或者在状态中保存一些东西,或者任何一般的操作。如果你想要简单的导航,我建议你使用<Link>
【参考方案1】:
我无法评论 React,但这是 SPA 的正确方法,在 React 中实现它应该是微不足道的。
简答
如果没有其他选项可用,请使用超链接 (<a>
) 在页面之间以及在加载其他内容时导航。
更简单地说:如果 URL 发生变化或您向页面添加大量信息,请使用超链接。
长答案
在您的问题中,您提到了 History API 和 react-router
。
因此,我假设函数 navigateToNextPage
会更改 URL。
我还假设我可以通过在浏览器中输入该 URL 来直接访问该页面。
考虑到这些假设,您应该使用:-
<a href="new-page-url" onClick=navigateToNextPage>Link</a>
显然你会停止默认操作(e.preventDefault()
或 React 等效项)。
关于为什么使用上述格式的几点:-
-
辅助功能 - 当我遇到带有屏幕阅读器的超链接时,我可以询问我的屏幕阅读器该链接会将我带到哪里,这令人放心,我不能用按钮做同样的事情。 这就是为什么我没有使用
#
作为超链接,而是添加了实际目的地。如果您看到href="#"
,几乎总是表明使用了错误的元素或使用不正确。在阅读您的 cmets 关于在导航之前执行某个操作之后仍然完全有效,执行您的操作然后重定向,它仍然是一天结束时的导航。
辅助功能 - 当我通过屏幕阅读器浏览网站时,我可能会决定循环浏览页面上的所有超链接以了解页面结构。 (例如,NVDA 修饰符 + K 以获取下一个链接)。我不太可能遍历页面上的所有按钮来查找导航。
辅助功能 - 如果我遇到一个链接,我希望页面会发生变化(甚至通过 AJAX)。如果我遇到一个按钮,我希望它在当前页面上执行一个操作。预期行为是可访问性的关键部分。
可访问性 - 超链接有一些重要的状态。 'visited' 是具有大量链接的页面上的关键之一,因为我可能想查看我之前阅读的内容并能够通过访问过的链接进行导航(例如 NVDA 修饰符 + K 对于所有未访问的链接)。按钮不公开此信息。重要的一点是,您也不能在 CSS 中使用 button:visited
为按钮设置样式,因此您会错过那里每个人的视觉线索。
辅助功能 - Space 键与 Enter 键。如果我登陆一个我希望按space
进行导航的链接,<button>
仅适用于 Enter 键,因此我可能会对页面没有更改的原因感到困惑。 (我假设此时您已经使用了 aria
的负载来说服我这个按钮是一个超链接)。
稳健性 - 如果您的网站功能有限当 javascript 失败时,超链接远比按钮好。 当 JavaScript 失败时它仍然可以工作,这尤其有用当 JavaScript 失败可能只是一个页面的临时加载问题,允许用户访问另一个正常运行的页面.
SEO - 我敢在 Stack Overflow 上谈论 SEO?耻辱!耻辱!耻辱! :-P - 但说真的,尽管谷歌在 JS 驱动的网站上可以做的事情非常聪明,但它仍然很难弄清楚只有 JavaScript 的链接将把它带到哪里。如果 SEO 对您很重要,请使用具有有效目的地的超链接,以便 Google 可以正确映射信息。
可能还有其他原因我忘了提及,但我想我已经说明了这一点。
使用 AJAX 在页面之间导航时需要考虑什么?
虽然不是你问题的一部分,但我想我会很快补充几点以确保完整性。
如果您使用的是 SPA 模式(因此会中断正常导航),则需要向用户发出页面正在加载的信号。例如我单击您的链接,您需要让我知道正在执行某个操作(正在加载.....),因为您使用 e.preventDefault()
或等效项拦截了正常的浏览器行为。
最简单的方法是在解释页面正在加载的区域上使用aria-live=assertive
。您可以谷歌如何正确实施。
此外,当新页面加载时,您需要管理焦点。
执行此操作的最佳方法是为每个具有tabindex="-1"
的页面添加一个级别 1 标题 (<h1>
)。
页面加载后,您在 JavaScript 导航函数中执行的最后一个操作是将焦点放在此标题上。
这有两个好处:
-
它让用户知道他们现在在哪里
它还让他们知道页面加载何时完成(因为大多数屏幕阅读器中的 AJAX 导航不会通知页面何时加载)。
通过使用tabindex="-1"
,这意味着标题不会被 JavaScript 以外的任何东西聚焦,因此不会干扰正常的文档流。
【讨论】:
喜欢你的回答。 爱爱爱它!正是我想要的 - 谢谢! 没问题,很高兴能帮上忙!【参考方案2】:你可以在点击<NavLink>
时做e.preventDefault()
做你的事。然后导航。 NavLink
在 html 中生成 <a>
标签,并在路由处于活动状态时默认提供 active
类。这允许您设置活动状态链接的样式。
import React from "react";
import NavLink, withRouter from "react-router-dom";
function Header(props)
const handleClick = e =>
e.preventDefault();
console.log("DO SOMETHING");
props.history.push(e.target.pathname);
;
return (
<ul>
<li>
<NavLink exact to="/" onClick=handleClick>
Home
</NavLink>
</li>
<li>
<NavLink to="/about" onClick=handleClick>
About
</NavLink>
</li>
<li>
<NavLink to="/topics" onClick=handleClick>
NavLink
</NavLink>
</li>
</ul>
);
export const HeaderNav = withRouter(Header);
工作示例:https://codesandbox.io/s/react-router-5-rqzqq
【讨论】:
我不明白投反对票的原因。它解决了问题? 我认为您投了反对票,因为它没有回答是使用按钮还是超链接。对我来说似乎有点苛刻,因为有人可能只是评论了这个让你修复它。 这似乎只是解释。如果这不仅仅是苛刻的原因,那是一件很糟糕的事情。使用<NavLink>
在 HTML 中生成 <a>
并在该路由中包含 active
类,允许您根据需要设置样式。我提供了工作示例¯_(ツ)_/¯【参考方案3】:
我建议您使用语义 HTML。这意味着尽可能地使用正确的 HTML 元素来达到预期目的。
更易于开发 - 您可以免费获得一些功能,而且可以说更容易理解。 在移动设备上更好 - 语义 HTML 的文件大小可以说比非语义意大利面条代码更轻,并且更容易做出响应。 有利于 SEO — 搜索引擎更重视标题、链接等中的关键字,而不是非语义中包含的关键字 s 等,以便客户更容易找到您的文档。
有more details
【讨论】:
以上是关于React SPA 中的锚点或按钮?的主要内容,如果未能解决你的问题,请参考以下文章