繁体   English   中英

在 Next.js 网站中打开一个页面作为覆盖

[英]Open a page in a Next.js website as an overlay

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

在此处输入图像描述

这是该过程的更详细说明。

  • 用户导航到 /list?keywords=widget 的列表页面
  • 用户点击产品
  • 产品的内容在叠加层上动画,但列表页面没有卸载,它仍然在产品页面下方
  • URL 栏更新以反映用户在 /products/123 上,但实际上并未加载产品页面。
  • 如果用户点击后退按钮,则覆盖消失。
  • 如果用户在覆盖打开时点击刷新按钮,他们将获得产品页面的 ssr 版本,下面的列表页面不再存在。

起初我以为我可以使用 Next/Router 上的 {shallow:true} 选项来使其工作,但文档特别说这仅适用于同一页面导航(使用不同的查询字符串)。

我唯一的想法是,我可以将链接设置为正确的,但在浏览器中劫持它以在历史 state 中的纯 javascript 中执行某些操作,但我不确定是否可以从等式中删除下一个路由器。

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

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

这是我的做法。

您需要创建一个可选的 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来呈现产品详细信息视图,而不是在叠加层中。

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

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

我们使用了两个 React Hook,一个用来保存 state,一个用来处理事件。 我们使用window.history.pushState来处理 URL

我不知道任何 Next.js,但是您可以将History.pushState()与模态结合使用吗?

您可以在推 URL 时添加 state 吗? 所以你可以跟踪以前的URL。

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

我知道我迟到了,但我从NextJS 文档中找到了另一种可能有用的方法。

在您的情况下,您可以通过这种方式更新您的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 是否可用,您可以显示或隐藏产品模式/叠加层。

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

希望这可以帮助。 干杯!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM