导航到 Layout 组件中的#id

Navigate to # id in Layout component

我正在使用 Gatbsy,我正在尝试为用户(使用屏幕阅读器)创建可访问性 link 以便能够导航到内容(跳过导航)。

我的布局组件(用于网站的每个页面)看起来像这样:


const Layout = ({ children }) => {

{/* hidden for brevity */} 

return (

 <>
   <a href="#main-content">Skip to content</a> {/* <-reference line */}

   {/* hidden for brevity */} 

   <main id="main-content">
      {children}
   </main>


   {/* hidden for brevity */}

 </>

);

}

当前行为:

如上面的代码示例所示,link 将为我“登陆”的页面生成一次,并且不会为我导航到的后续页面更新: 前任。登陆 'blog' 页面我的 link 将指向 localhost:9000/blog#main-content 并导航到 'about' 页面不会使布局的该部分重新呈现(这很可能是正常行为).

我也试过使用 useRef,但在渲染过程中得到的引用项目是 undefined

完成此任务的方法是什么(考虑到页面是服务器端呈现的)?有没有一种方法可以在不传递完整路由路径的情况下在标签内使用它?

正如我在上面评论的那样,Gatsby 的 <Link> 组件扩展自 @reach/router(来自 React)不允许导航到任何参数。来自 docs:

Neither <Link> nor navigate can be used for in-route navigation with a hash or query parameter. If you need this behavior, you should either use an anchor tag or import the @reach/router package—which Gatsby already depends upon—to make use of its navigate function.

如果您使用 navigate,例如,navigate("/blog#main-content") 它将重定向到 /blog,省略参数,因为它是不允许的。

在你的情况下,useRef 方法不会直接使用,因为在你创建它的那一刻,它还没有呈现,所以你可以使用 useRef 钩子方法和 useEffect 挂钩,以确保加载 DOM 树或使用一些手动触发器:

const Layout = ({ children }) => {
  const mainRef= useRef(null);


  const navigateToContent= () => {
    mainRef.current.scrollIntoView(); //manual trigger 
  }

 useEffect(()=>{
    mainRef.current.scrollIntoView();  //automatic trigger 
 }, [])
 
{/* hidden for brevity */} 

return (

 <>
   <div onClick={navigateToContent}>Skip to content</div> 

   {/* hidden for brevity */} 

   <main id="main-content" ref={mainRef}>
      {children}
   </main>


   {/* hidden for brevity */}

 </>

);

}

在上面的代码片段中,我添加了两种不同的方法,请选择适合您要求的方法。关键部分是正确设置main标签的引用,初始设置为null以避免路由变化时出现补水问题。

手动触发,只需要在你的Skip to content中调用一个函数(navigateToContent) 使用 scrollIntoView() 内置函数滚动到引用的元素。

自动触发,只是使用相同的想法,但是一旦加载 DOM 树(useEffect 与空 deps[])就会触发该功能。


问题已解决如下:

Actually changing this <Link to="/#main-content">Skip to content</Link> to this <Link to="#main-content">Skip to content</Link> (removing the /) works perfectly fine