当我导航到新页面时,“到达路由器”向下滚动到页面内容的标题上方(如果内容足够长)。我假设这是为了可访问性,但对于我的应用程序不是必需的,并且实际上是很麻烦的。可以禁用此行为吗?
请注意,我所说的是“到达路由器而不是React Router”。
答案 0 :(得分:10)
尝试使用<Router primary={false}>
,它不会关注路线组件。
https://reach.tech/router/api/Router
主要的:bool
默认为true。主路由器将专注于位置转换。如果为false,将不会管理焦点。这对于呈现为边,标头,面包屑等的路由器很有用,但对于主要内容却没有。
答案 1 :(得分:3)
在@Marcus答案的基础上,您可以使用useLayoutEffect()
而不是useEffect()
来消除问题-通过这种方式,可以在完全渲染DOM之后执行滚动操作,因此您不必得到奇怪的“反弹”。
// ScrollToTop.js
import React from 'react'
export const ScrollToTop = ({ children, location }) => {
React.useLayoutEffect(() => window.scrollTo(0, 0), [location.pathname])
return children
}
答案 2 :(得分:1)
我不得不使用多种方法使它起作用。即使设置了primary={false}
,在某些情况下页面也不会滚动到顶部。
<Router primary={false}>
<ScrollToTop path="/">
<Home path="/" />
<Contact path="contact-us" />
<ThankYou path="thank-you" />
<WhoWeAre path="who-we-are" />
</ScrollToTop>
</Router>
这基于React Router's scroll restoration guide。
没有primary={false}
的情况下,滚动到顶部组件仍然可以使用,但是会引起混乱,因为它使路线集中,然后调用window.scrollTo
。
// ScrollToTop.js
import React from 'react'
export const ScrollToTop = ({ children, location }) => {
React.useEffect(() => window.scrollTo(0, 0), [location.pathname])
return children
}
答案 3 :(得分:1)
在解决OP问题的同时,这里的最高答案可能不是大多数人想要的解决方案,因为它关闭了Reach路由器最重要的可访问性功能。
由于可访问性原因,到达路由器将匹配的<Route>
的内容集中在路由更改为的事实上-因此,当出现以下情况时,屏幕阅读器等可以定向到最新更新的相关内容您导航到新页面。
它使用HTMLElement.focus()
来执行此操作-see the MDN docs here。
问题是默认情况下,此函数滚动到要聚焦的元素。 有一个preventScroll
参数,可以用来关闭此行为,但是浏览器对此行为的支持不好,并且无论如何,Reach Router都不使用它。
primary
上的Router
道具用于关闭您可能拥有的所有嵌套 <Router>
的行为-它不是不是旨在用于您的主要(主要)<Router>
上-因此使用该名称。
将此false
设置在主要<Router>
上,如最佳答案所示,“有效”是指它停止了 scrolling 行为,但它可以通过以下方式实现此目的只需完全关闭聚焦行为,就会破坏可访问性功能。就像我说的那样,如果您这样做的话,您首先就要打破使用Reach Router的主要原因之一。
基本上,HTMLElement.focus()
的副作用-滚动到焦点元素-似乎是不可避免的。因此,如果要使用可访问性功能,则必须采取滚动行为。
但是,尽管如此,可能有解决方法。如果您在每次更改路线时使用window.scrollTo(0, 0)
手动滚动到页面顶部,我相信从可访问性的角度来看不会“破坏”聚焦功能,而会从UX的角度“解决”滚动行为。
当然,这是一个有点棘手且必须执行的解决方法,但我认为这是在不破坏可访问性的情况下解决此问题的最佳方法(也许是唯一的方法)。
这是我的实现方式
class OnRouteChangeWorker extends React.Component {
componentDidUpdate(prevProps) {
if (this.props.location.pathname !== prevProps.location.pathname) {
this.props.action()
}
}
render() {
return null
}
}
const OnRouteChange = ({ action }) => (
{/*
Location is an import from @reach/router,
provides current location from context
*/}
<Location>
{({ location }) => <OnRouteChangeWorker location={location} action={action} />}
</Location>
)
const Routes = () => (
<>
<Router>
<LayoutWithHeaderBar path="/">
<Home path="/" />
<Foo path="/foo" />
<Bar path="/bar" />
</LayoutWithHeaderBar>
</Router>
{/*
must come *after* <Router> else Reach router will call focus()
on the matched route after action is called, undoing the behaviour!
*/}
<OnRouteChange action={() => { window.scrollTo(0, 0) } />
</>
)
答案 4 :(得分:0)
必须有另一件事导致此。就像@Vinicius所说。因为primary={false}
对于我的应用程序确实有效。我有一个小应用程序,下面是我的路线。
<Router primary={false}>
<Home path="/" />
<Dashboard path="dashboard" />
<Users path="users" />
<Sales path="sales" />
<Settings path="settings" />
</Router>
答案 5 :(得分:0)
使用primary={false}
不能解决所有情况。常见的解决方案是包装页面并使用useEffect
获得结果。正如某人指出的那样,虽然我从未发生过这种情况,但可能还是会遇到闪光问题,所以请尝试运气。
<PageWrapper Component={About} path="/about" />
const PageWrapper = ({ path, Component }) => {
useEffect(() => {
window.scrollTo(0, 0)
}, [path])
return <Component path={path} />
}
请注意,在React Router中,您可以按照here的说明使用history.listen
。我没有检查“到达路由器”中是否有类似的解决方案,但是该解决方案会更好。
答案 6 :(得分:0)
我从中制作了一个npm软件包以简化集成:https://www.npmjs.com/package/reach-router-scroll-top