在 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} 选项来让它工作,但文档明确说这只适用于相同的页面导航(不同的查询字符串)。
我唯一的想法是我可以将 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。
这样做可以减少代码开销,您也可以正常使用下一个链接而无需手动更改路由
希望这对您有所帮助。干杯!
我有一个可以搜索的网站。我希望用户能够单击搜索结果并在叠加层中打开产品,而不是重新加载整个页面,但是我希望 url 栏中的 url 成为正确的产品页面,以便用户复制并粘贴它或在新选项卡中打开它,他们将获得产品页面。我还希望后退按钮在这两种情况下都能正常工作。
这里有一个更详细的过程解释。
- 用户导航到位于 /list?keywords=widget 的列表页面
- 用户点击产品
- 产品的内容在叠加层上呈现动画,但列表页面没有卸载,它仍然在产品页面下方
- URL 栏更新以反映用户正在 /products/123 但产品页面实际上并未加载。
- 如果用户点击后退按钮,叠加层就会消失。
- 如果用户在叠加层打开时点击刷新按钮,他们将获得产品页面的 ssr 版本,下面的列表页面不再存在。
我一开始以为我可以在 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。
这样做可以减少代码开销,您也可以正常使用下一个链接而无需手动更改路由
希望这对您有所帮助。干杯!