代码之家  ›  专栏  ›  技术社区  ›  Evanss

停止到达路由器在导航到新页面后向下滚动页面

  •  3
  • Evanss  · 技术社区  · 5 年前

    Reach Router

    1 回复  |  直到 5 年前
        1
  •  10
  •   davnicwil    4 年前

    在解决OP问题时,这里的首要答案可能不是大多数人想要的解决方案,因为它关闭了Reach路由器最重要的可访问性功能。

    事实上,Reach router将重点放在匹配的内容上 <Route> 在一条路线上,改变是必要的 -因此,当您导航到新页面时,屏幕阅读器等可以指向最新更新的相关内容。

    HTMLElement.focus() see the MDN docs here .

    A. preventScroll

    背景 primary={false} 嵌套 <Router> 你可能有——是的 打算设置 false 在主(主)屏幕上 <路由器> --因此得名。

    那么,背景呢 primary={false} 在你的初选上 <路由器>

    HTMLElement.focus() -滚动到焦点元素-是不可避免的。因此,如果您想要可访问性功能,您必须使用它的滚动行为。

    但尽管如此,还是有解决办法的。如果使用手动滚动到页面顶部 window.scrollTo(0, 0)

    当然,这是一个有点黑客和必要的解决办法,但我认为这是最好的(也许是唯一的)解决方案,这个问题不破坏可访问性。

    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) } />
      </>
    )
    
        2
  •  15
  •   Vinicius    5 年前

    试用 <Router primary={false}>

    https://reach.tech/router/api/Router

    小学:布尔

    默认为true。主路由器将管理对位置转换的关注。如果为false,则不会管理焦点。这对于呈现为旁白、标题、面包屑等的路由器很有用,但不是主要内容。

    :如果您担心破坏可访问性,请参阅以下答案: https://stackoverflow.com/a/56996986/428780

        3
  •  4
  •   Gareth Kloeden    5 年前

    在@Marcus answer的基础上,你可以用 useLayoutEffect() 而不是 useEffect()

    // ScrollToTop.js
    import React from 'react'
    
    export const ScrollToTop = ({ children, location }) => {
      React.useLayoutEffect(() => window.scrollTo(0, 0), [location.pathname])
      return children
    }
    
        4
  •  3
  •   Marcus Wood    5 年前

    我必须综合运用各种方法才能使它发挥作用。即使设置 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} ,但它会导致jank从它关注的路线开始,然后呼叫 window.scrollTo .

    // ScrollToTop.js
    import React from 'react'
    
    export const ScrollToTop = ({ children, location }) => {
      React.useEffect(() => window.scrollTo(0, 0), [location.pathname])
      return children
    }
    
    
        5
  •  0
  •   Erdal SATIK    5 年前

    primary={false} 真的很有效。我有一个小应用程序和我的路线如下。

    <Router primary={false}>
      <Home path="/" />
      <Dashboard path="dashboard" />
      <Users path="users" />
      <Sales path="sales" />
      <Settings path="settings" />
    </Router>
    
        6
  •  0
  •   lehoang    4 年前

    使用 primary={false} 并不能解决所有的问题。一个常见的解决方案是包装页面并使用 useEffect

    <PageWrapper Component={About} path="/about" />
    
    const PageWrapper = ({ path, Component }) => {
      useEffect(() => {
        window.scrollTo(0, 0)
      }, [path])
    
      return <Component path={path} />
    }
    

    请注意,在React路由器中,您可以使用 history.listen 如前所述 here . 我并没有检查Reach路由器中是否有类似的解决方案,但该解决方案将更为优化。

        7
  •  0
  •   Dark Smile    3 年前

    我用它制作了一个npm包,以简化集成: https://www.npmjs.com/package/reach-router-scroll-top

    推荐文章