在 Next.js 网站中打开一个页面作为叠加层

Open a page in a Next.js website as an overlay

我有一个可以搜索的网站。我希望用户能够单击搜索结果并在叠加层中打开产品,而不是重新加载整个页面,但是我希望 url 栏中的 url 成为正确的产品页面,以便用户复制并粘贴它或在新选项卡中打开它,他们将获得产品页面。我还希望后退按钮在这两种情况下都能正常工作。

这里有一个更详细的过程解释。

我一开始以为我可以在 Next/Router 上使用 {shallow:true} 选项来让它工作,但文档明确说这只适用于相同的页面导航(不同的查询字符串)。

我唯一的想法是我可以将 link 设置为适当的但在浏览器中劫持它以在历史状态中以纯 javascript 做一些事情但我是不确定下一个路由器是否可以从等式中删除。

澄清一下,我不是在寻求产品页面或叠加层本身的帮助,我可以轻松创建在两种情况下显示相同内容的共享组件,特别是路由和 URL我请求帮助的问题。

任何帮助,即使是正确方向的指示,我们也将不胜感激。

我什么都不知道 Next.js,但是你可以将 History.pushState() 与模态结合使用吗?

您可以在按下 URL 时添加状态吗?这样你就可以跟踪之前的URL.

history.push({
  pathname: PATH_NAME,
  state: {
    from: PREV_URL
  },
});

我已经为您制作了一个代码沙箱,希望对您有所帮助。

https://codesandbox.io/s/overlay-4qhfb-4qhfb

我们使用了两个 React Hooks,一个保持状态,一个处理事件。我们使用 window.history.pushState 来处理 URL

这是我的做法。

您需要创建一个 optional catch all route。即:pages/search/[[searchParams]].tsx

import { useRouter } from 'next/router';
import { GetServerSidePropsContext } from 'next';
import { ProductsView, ProductDetailsView } from '@/views';

export async function getServerSideProps({
  params,
}: GetServerSidePropsContext) {
  const [productId = null] = (params?.searchParams as string[]) || [];
  return {
    props: {
      productId,
    },
  };
}

interface Props {
  productId?: string;
}

function SearchProductsPage({ productId }: Props) {
  const router = useRouter();

  // You could use next/link in your views instead of using next/router
  const onViewDetails = (productDetailsId: string) => {
    router.push(productDetailsId, `product/${productDetailsId}`).catch((e) => {
      console.error(e);
    });
  };
  // Going back to /search will remove the productId and the overlay view will be removed 
  const onClose = () => {
    router.push('/search').catch((e) => {
      console.error(e);
    });
  };

  // If you have a productId (catch from URL and received via Props)
  // it will render the Product details view which contains the overlay and the product details
  return (
    <>
      <ProductsView onViewDetails={onViewDetails} />
      {productId && <ProductDetailsView productId={productId} onClose={onClose} />}
    </>
  );
}

export default SearchProductsPage;

请注意,路由到 /product/${productDetailsId} 而不是 product/${productDetailsId} 会给您一个错误。所以你用这段代码,你最终会得到 URL 就像 /search/product/1 而不是 /product/1.

但是您可以创建一个单独的页面,即 pages/product/[productId].tsx 呈现产品详细信息视图,而不是在叠加层中。

我知道我来晚了,但我从 NextJS Documentation 中找到了另一种方法,您可能会觉得有用。

在你的情况下,你可以这样更新你的 next.config 文件

module.exports = {
  async rewrites() {
    return [
      {
        source: '/product/:id*',
        destination: '/search', // The :id parameter isn't used here so will be automatically passed in the query
      },
    ]
  },
}

然后在搜索页面中,您可以通过这种方式访问​​产品的 id

const router = useRouter();
const { query } = router;
const productID = query?.id;

根据产品 ID 是否可用,您可以显示或隐藏产品 modal/overlay。

这样做可以减少代码开销,您也可以正常使用下一个链接而无需手动更改路由

希望这对您有所帮助。干杯!