如何在下一个 js 中返回时更改滚动行为?

Mah*_*aji 10 javascript reactjs next.js

我在索引 js 中获取帖子列表,如下所示:

const Index = (props) => {
    return (
        <div>
            {props.posts.map((each) => {
                return (
                    <Link scroll={false} as={`/post/${each.id}`} href="/post/[id]" key={each.id}>
                        <a>
                            <h1>{each.title}</h1>
                        </a>
                    </Link>
                );
            })}
        </div>
    );
};

export async function getStaticProps() {
    const url = `https://jsonplaceholder.typicode.com/posts`;
    const res = await axios.get(url);

    return {
        props: { posts: res.data }
    };
}
Run Code Online (Sandbox Code Playgroud)

当用户单击任何链接时,它会转到帖子页面:

function post({ post }) {
    return (
            <h1>{post.id}</h1>
    );
}

export async function getServerSideProps({ query }) {
    const { id } = query;
    const res = await Axios.get(`https://jsonplaceholder.typicode.com/posts/${id}`);

    return {
        props: { post: res.data}
    };
}
Run Code Online (Sandbox Code Playgroud)

问题是当我单击返回时,滚动位置重置为顶部并获取所有帖子。我包含scroll={false}在链接中,但它不起作用。

当用户从帖子页面单击返回时,如何防止滚动重置?

Dev*_*evo 21

事实上,Next.js 内置了返回上一页时恢复滚动位置的支持。我们可以通过编辑以下内容来简单地启用它next.config.js

module.exports = {
  experimental: {
    scrollRestoration: true,
  },
}
Run Code Online (Sandbox Code Playgroud)

  • 嗯,这对我不起作用。 (7认同)

Mil*_*les 5

scroll={false}不保持上一页的滚动;它根本不会改变滚动,这意味着滚动将是您链接的页面的滚动。您可以使用scroll={false}覆盖将scrollY 设置为0 的默认行为,以便您可以实现自己的行为。

这是我实现恢复滚动位置的方法。这与 Max william 的答案非常相似,但使用useRef而不是useState. 与useRef.useStateuseRefuseState​ 每次用户更改滚动时,我们都会将值更新为当前滚动位置,如果我们使用 useState,这将意味着大量无用的重新渲染。

首先,定义一个 UserContext 组件,以便轻松地将滚动数据从 _app.js 组件传递到您需要的任何地方:

import { createContext } from 'react';

const UserContext = createContext();

export default UserContext;
Run Code Online (Sandbox Code Playgroud)

然后,在您的 _app.js 组件中,使用 UserContext 包装页面并创建 useRef 属性来存储滚动位置。

import { useRef } from 'react';
import UserContext from '../components/context'

function MyApp({ Component, pageProps }) {

  const scrollRef = useRef({
      scrollPos: 0
  });
    
  return (
      <Layout>
          <UserContext.Provider value={{ scrollRef: scrollRef }}>
              <Component {...pageProps} />
          </UserContext.Provider>
      </Layout>
  )
}

export default MyApp
Run Code Online (Sandbox Code Playgroud)

然后,在您想要恢复滚动位置的任何页面组件内(即您想要返回并看到与离开时相同的滚动位置的页面),您可以放置​​此代码来设置页面的滚动位置并将滚动事件绑定到函数以更新存储的滚动位置。

import UserContext from '../components/context'
import { useContext } from 'react';

export default function YourPageComponent() {

  const { scrollRef } = useContext(UserContext);

  React.useEffect(() => {
    
    //called when the component has been mounted, sets the scroll to the currently stored scroll position
    window.scrollTo(0, scrollRef.current.scrollPos);

    const handleScrollPos = () => {
      //every time the window is scrolled, update the reference. This will not cause a re-render, meaning smooth uninterrupted scrolling.
      scrollRef.current.scrollPos = window.scrollY
    };

    window.addEventListener('scroll', handleScrollPos);

    return () => {
      //remove event listener on unmount
      window.removeEventListener('scroll', handleScrollPos);
    };
  });

  return (
    //your content
  )
}
Run Code Online (Sandbox Code Playgroud)

最后一件小事是scroll={false}在链接组件上使用它链接回 YourPageComponent。这样 next.js 就不会自动将滚动设置为 0,从而覆盖我们所做的一切。

感谢 Max william 对大部分结构的回答,我的主要更改是使用 useRef。我还添加了一些解释,希望对您有所帮助!