NextJs 13实验性应用程序目录哈希在路由中不会重定向到哈希ID。

huangapple go评论76阅读模式
英文:

NextJs 13 Experimental App Dir Hash in routes not directing to the hash id

问题

我使用 Next.js 13 与实验性的 App 目录,但不确定我面临的问题是否与我正在面对的问题有关。在我的主页上有一个 id 为 "faqs" 的元素,当我点击链接时,可以成功跳转到该链接,但在浏览器中没有发生任何滚动。如果我在另一个页面上点击该链接,它会将我带到具有正确 URL 的主页,但仍然停留在页面顶部,不会滚动到指定的 id 处。我已经按照文档建议实现了 scroll={false},但没有任何效果。

这是相关代码部分的摘要:

"use client"
import React, { useState } from "react"
import { useRouter } from "next/navigation"
import Link from "next/link"

const Navigation = () => {
  const router = useRouter()
  ...
}

在返回部分:

<Link scroll={false} href="/#faqs">FAQS</Link>

我甚至尝试过:

<button type="button" onClick={() => router.push("/#faqs")}>FAQS</button>

在 React 中,哈希标识符功能相当正常,但在 Next.js 中,即使仅在客户端渲染中也似乎复杂。如果有人知道我做错了什么,或者是否有可行的解决方法,我会非常感激。提前感谢您的帮助。如果我漏掉了什么,请告诉我。

英文:

I am using Nextjs 13 with the experimental App Dir but am not sure if this problem I am facing has anything to do with the issue I am facing. I have an id in my home page of "faqs" and when I click on the link, I can see it successfully goes to that link but does nothing in the browser. If I am on another page, I click the link and it takes me to the home page with the correct url but still stays on the top of the page and does not scroll to the indicated id. I did implement scroll={false} as suggested in the documentation but it makes no difference.

Here is a snippet of the relevant code parts:

&quot;use client&quot;
import React, { useState } from &quot;react&quot;
import { useRouter } from &quot;next/navigation&quot;
import Link from &quot;next/link&quot;

const Navigation = () =&gt; {
  const router = useRouter()
 ...

In the return:

 &lt;Link scroll={false} href=&quot;/#faqs&quot;&gt;FAQS&lt;/Link&gt;

I Even tried:

&lt;button type=&quot;button&quot; onClick={() =&gt; router.push(&quot;/#faqs&quot;)}&gt;FAQS&lt;/button&gt;

In React the hash works fairly well but in next js, even only in client rendering it seems convoluted. If anyone knows what I am doing wrong or if there is a viable work around, I would sure appreciate it.
Thank you in advance.
If I am missing anything, please let me know.

答案1

得分: 3

我经常使用标签,计划在将来的项目中开始使用应用程序目录,所以我深入研究了这个问题,情况并不太好。显然,NextJS 在客户端使用不同的包来处理应用程序目录组件,称为 "next/navigation",它与 "next/router" 非常不同。此外,当使用 "next/link" 元素时,NextJS 在 location.hash 更改但 location.pathname 不更改时不会触发 onRouteChangeComplete 事件。

因此,为了检测哈希值的更改并滚动到关联的元素,我最终不得不实施这个 hack:

"use client"
import { Inter } from '@next/font/google'
import paragraph from './paragraph'
import Link from 'next/link'
import { useEffect, useState } from 'react'

const inter = Inter({ subsets: ['latin'] })

export default function Home() {
  const [navClick, setNavClick] = useState(false);

  useEffect(() => {
    setTimeout(() => {
      const hash = window.location.hash;
      if (hash) document.querySelector(hash).scrollIntoView();
    }, 0);
  }, [navClick])

  const toggleNavClick = () => setNavClick((oldVal) => !oldVal);

  return (
    <main>
      <nav>
        <ul>
          <li>
            <Link href="/#one" onClick={toggleNavClick}>Section One</Link>
          </li>
          <li>
            <Link href="/#two" onClick={toggleNavClick}>Section Two</Link>
          </li>
          <li>
            <Link href="/#three" onClick={toggleNavClick}>Section Three</Link>
          </li>
        </ul>
      </nav>
      <div className="container">
        <section id="one">
          <h1>Section One</h1>
          <div dangerouslySetInnerHTML={{ __html: paragraph }} />
        </section>
        <section id="two">
          <h1>Section Two</h1>
          <div dangerouslySetInnerHTML={{ __html: paragraph }} />
        </section>
        <section id="three">
          <h1>Section Three</h1>
          <div dangerouslySetInnerHTML={{ __html: paragraph }} />
        </section>
      </div>
    </main>
  )
}

由于无法检测哈希值的更改,因为没有触发事件,所以我基本上通过在每次点击链接时切换 navClick 来创建了一个事件。导航逻辑包含在 setTimeout() 函数中,因为它在更新 window.location 后触发。

仓库: https://github.com/designly1/next-hash-test
演示: https://next-hash-test.vercel.app/

英文:

I use hashtags a lot and I plan to start using the app directory in future projects, so I dug into this and it's not pretty. Apparently, NextJS uses a different package for app directory components client-side called "next/navigation". It's very different from "next/router". Also, when using "next/link" elements, NextJS does not trigger the onRouteChangeComplete event when location.hash changes but location.pathname does not.

So, in order to detect a hash change and scroll to the associated element, I finally had to implement this hack:

&quot;use client&quot;
import { Inter } from &#39;@next/font/google&#39;
import paragraph from &#39;./paragraph&#39;
import Link from &#39;next/link&#39;
import { useEffect, useState } from &#39;react&#39;

const inter = Inter({ subsets: [&#39;latin&#39;] })

export default function Home() {
  const [navClick, setNavClick] = useState(false);

  useEffect(() =&gt; {
    setTimeout(() =&gt; {
      const hash = window.location.hash;
      if (hash) document.querySelector(hash).scrollIntoView();
    }, 0);
  }, [navClick])

  const toggleNavClick = () =&gt; setNavClick((oldVal) =&gt; !oldVal);

  return (
    &lt;main&gt;
      &lt;nav&gt;
        &lt;ul&gt;
          &lt;li&gt;
            &lt;Link href=&quot;/#one&quot; onClick={toggleNavClick}&gt;Section One&lt;/Link&gt;
          &lt;/li&gt;
          &lt;li&gt;
            &lt;Link href=&quot;/#two&quot; onClick={toggleNavClick}&gt;Section Two&lt;/Link&gt;
          &lt;/li&gt;
          &lt;li&gt;
            &lt;Link href=&quot;/#three&quot; onClick={toggleNavClick}&gt;Section Three&lt;/Link&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/nav&gt;
      &lt;div className=&quot;container&quot;&gt;
        &lt;section id=&quot;one&quot;&gt;
          &lt;h1&gt;Section One&lt;/h1&gt;
          &lt;div dangerouslySetInnerHTML={{ __html: paragraph }} /&gt;
        &lt;/section&gt;
        &lt;section id=&quot;two&quot;&gt;
          &lt;h1&gt;Section Two&lt;/h1&gt;
          &lt;div dangerouslySetInnerHTML={{ __html: paragraph }} /&gt;
        &lt;/section&gt;
        &lt;section id=&quot;three&quot;&gt;
          &lt;h1&gt;Section Three&lt;/h1&gt;
          &lt;div dangerouslySetInnerHTML={{ __html: paragraph }} /&gt;
        &lt;/section&gt;
      &lt;/div&gt;
    &lt;/main&gt;
  )
}

Since the hash change cannot be detected because no event is triggered, I basically created an event by toggling navClick each time a link is clicked. The navigation logic is enclosed in setTimeout() function because it triggers after window.location is updated.

Repo: https://github.com/designly1/next-hash-test
Demo: https://next-hash-test.vercel.app/

答案2

得分: 0

我的解决方法是不使用Link组件:

<a href="#faqs">FAQS</a>
英文:

My workaround is to not use the Link component:

&lt;a href=&quot;#faqs&quot;&gt;FAQS&lt;/a&gt;

答案3

得分: 0

以下是翻译后的代码部分:

const scrollToHeader = (anchorId: string) => {
  const headerElement = document.getElementById(anchorId);
  if (headerElement) {
    const offset = 100;
    const scrollPosition = headerElement.getBoundingClientRect().top + window.scrollY - offset;

    window.scrollTo({
      top: scrollPosition,
      behavior: "smooth",
    });
  }
};
<Link
  key={headerId}
  className="text-sm font-semibold text-primary hover:underline"
  href={`#${headerId}`}
  scroll={false}
  onClick={(e) => {
    scrollToHeader(headerId);
    onLinkClick?.();
  }}>
  {parser(String(formattedHeaderText))}
</Link>
英文:

My solution for scroll to particular header is this.

  const scrollToHeader = (anchorId: string) =&gt; {
const headerElement = document.getElementById(anchorId);
if (headerElement) {
const offset = 100;
const scrollPosition = headerElement.getBoundingClientRect().top + window.scrollY - offset;
window.scrollTo({
top: scrollPosition,
behavior: &quot;smooth&quot;,
});
}
};
&lt;Link
key={headerId}
className=&quot;text-sm font-semibold text-primary hover:underline&quot;
href={`#${headerId}`}
scroll={false}
onClick={(e) =&gt; {
scrollToHeader(headerId);
onLinkClick?.();
}}&gt;
{parser(String(formattedHeaderText))}
&lt;/Link&gt;

huangapple
  • 本文由 发表于 2023年2月18日 08:03:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/75490284.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定