Next.js 13页面内嵌套路由组件:无跳转切换产品分类方案问询
在Next.js 13中实现带分类子导航的产品概览页面
要实现点击分类子导航切换内容、更新URL但不跳转页面的效果,核心是利用Next.js的客户端路由能力结合动态路由,下面是具体实现步骤:
1. 规划路由结构
给不同分类设置独立路由,比如:
- 男装:
/products/men - 女装:
/products/women - 全部商品:
/products
在App Router目录下创建如下结构:
app/ ├─ products/ │ ├─ [category]/ │ │ └─ page.js │ ├─ layout.js │ └─ page.js
2. 编写布局组件(保持页面其他部分不变)
app/products/layout.js作为产品页的布局容器,放置头部、侧边栏等不需要随分类切换的内容,子内容会在children中渲染:
// app/products/layout.js export default function ProductsLayout({ children }) { return ( <div className="product-page-container"> {/* 头部导航 */} <header>品牌商城</header> <main>{children}</main> {/* 页脚 */} <footer>版权信息</footer> </div> ); }
3. 实现分类子导航组件
创建客户端组件SubNavigation.js,使用useRouter和useParams实现点击切换路由、高亮当前分类:
// app/components/SubNavigation.js 'use client'; import { useRouter, useParams } from 'next/navigation'; const categories = [ { name: '全部', slug: '' }, { name: '男装', slug: 'men' }, { name: '女装', slug: 'women' }, ]; export default function SubNavigation() { const router = useRouter(); const { category } = useParams(); const handleCategoryClick = (slug) => { // 切换路由,不刷新页面 const path = slug ? `/products/${slug}` : '/products'; router.push(path); }; return ( <div className="sub-nav"> {categories.map((item) => ( <button key={item.slug} onClick={() => handleCategoryClick(item.slug)} className={`nav-item ${category === item.slug || (!category && item.slug === '') ? 'active' : ''}`} > {item.name} </button> ))} </div> ); }
4. 编写分类页面逻辑
- 全部商品页面(
app/products/page.js):
// app/products/page.js import SubNavigation from '@/app/components/SubNavigation'; import ProductList from '@/app/components/ProductList'; // 获取全部商品数据 async function getAllProducts() { // 这里替换为实际的API请求或数据查询 const res = await fetch('https://api.example.com/products'); return res.json(); } export default async function AllProductsPage() { const products = await getAllProducts(); return ( <div> <SubNavigation /> <ProductList products={products} /> </div> ); }
- 分类商品页面(
app/products/[category]/page.js):
// app/products/[category]/page.js import SubNavigation from '@/app/components/SubNavigation'; import ProductList from '@/app/components/ProductList'; // 根据分类获取商品数据 async function getProductsByCategory(category) { // 这里替换为实际的API请求或数据查询 const res = await fetch(`https://api.example.com/products?category=${category}`); return res.json(); } export default async function CategoryProductsPage({ params }) { const products = await getProductsByCategory(params.category); return ( <div> <SubNavigation /> <ProductList products={products} /> </div> ); }
5. 商品列表组件(通用)
创建ProductList.js负责渲染商品内容:
// app/components/ProductList.js export default function ProductList({ products }) { return ( <div className="product-grid"> {products.map((product) => ( <div key={product.id} className="product-card"> <h3>{product.name}</h3> <p>¥{product.price}</p> </div> ))} </div> ); }
关键说明
- 客户端路由:通过
useRouter的push方法修改URL,Next.js会在客户端处理导航,不会刷新整个页面,布局组件保持不变。 - 动态路由与参数:
useParams获取当前分类参数,用于高亮子导航和请求对应分类的数据。 - 服务端渲染:页面组件默认是服务端组件,可直接在组件内异步获取数据,保证首屏性能。
内容的提问来源于stack exchange,提问作者Rengkat
相关产品推荐
相关产品推荐

