Chapter 06

布局与导航

用 Card/Separator/Tabs/Accordion/Sheet/Sidebar 搭建响应式页面骨架,理解可组合布局组件的拼装方式。

6.1 关键概念

复合组件(Compound Components)
一组配合使用的子组件,如 Card = Card + CardHeader + CardTitle + CardContent + CardFooter,共享上下文、可自由排列,比"一大堆 props"更灵活。
Card
内容容器,带边框/圆角/内边距,是仪表盘、列表项、表单区块的基础卡片单元。
Separator
Radix 的分隔线,横或竖,带 role="separator",可标记 decorative 让屏幕阅读器忽略。
Tabs
选项卡切换,Tabs + TabsList + TabsTrigger + TabsContent,键盘方向键切换、ARIA 完备。
Accordion
手风琴折叠面板,type="single"|"multiple" 控制单开或多开,适合 FAQ、设置分组。
Sheet
从屏幕边缘滑入的抽屉(基于 Dialog),常用于移动端导航、侧边筛选面板,可指定 side
Sidebar
shadcn 的完整侧边栏方案,含 SidebarProvider(管理折叠状态)、SidebarSidebarTrigger,自带移动端 Sheet 降级与快捷键。

6.2 安装

$ npx shadcn@latest add card separator tabs accordion sheet sidebar

6.3 Card:内容容器

import {
  Card, CardHeader, CardTitle, CardDescription,
  CardContent, CardFooter,
} from "@/components/ui/card";

<Card className="w-[360px]">
  <CardHeader>
    <CardTitle>创建项目</CardTitle>
    <CardDescription>一步部署你的新项目。</CardDescription>
  </CardHeader>
  <CardContent>
    <p className="text-sm text-muted-foreground">这里放表单或内容。</p>
  </CardContent>
  <CardFooter className="flex justify-between">
    <Button variant="outline">取消</Button>
    <Button>部署</Button>
  </CardFooter>
</Card>

6.4 Tabs:选项卡

import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";

<Tabs defaultValue="account" className="w-[400px]">
  <TabsList className="grid w-full grid-cols-2">
    <TabsTrigger value="account">账户</TabsTrigger>
    <TabsTrigger value="password">密码</TabsTrigger>
  </TabsList>
  <TabsContent value="account">账户设置面板</TabsContent>
  <TabsContent value="password">修改密码面板</TabsContent>
</Tabs>

6.5 Accordion:折叠面板

import {
  Accordion, AccordionContent, AccordionItem, AccordionTrigger,
} from "@/components/ui/accordion";

<Accordion type="single" collapsible className="w-full">
  <AccordionItem value="item-1">
    <AccordionTrigger>它可访问吗?</AccordionTrigger>
    <AccordionContent>是。遵循 WAI-ARIA 规范。</AccordionContent>
  </AccordionItem>
  <AccordionItem value="item-2">
    <AccordionTrigger>能改样式吗?</AccordionTrigger>
    <AccordionContent>当然,代码是你的。</AccordionContent>
  </AccordionItem>
</Accordion>

6.6 Sheet:边缘抽屉

import {
  Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger,
} from "@/components/ui/sheet";

<Sheet>
  <SheetTrigger asChild><Button variant="outline">打开菜单</Button></SheetTrigger>
  <SheetContent side="left">
    <SheetHeader><SheetTitle>导航</SheetTitle></SheetHeader>
    <nav className="mt-4 grid gap-2">
      <a href="#">仪表盘</a><a href="#">设置</a>
    </nav>
  </SheetContent>
</Sheet>
side 可取四个方向

side="left" | "right" | "top" | "bottom"。移动端汉堡菜单常用 left,购物车/详情常用 right,筛选面板常用 bottom。

6.7 Sidebar:完整侧边栏

// app/layout.tsx —— 用 Provider 包裹
import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar";
import { AppSidebar } from "@/components/app-sidebar";

<SidebarProvider>
  <AppSidebar />
  <main className="flex-1">
    <SidebarTrigger />  // 折叠/展开按钮
    {children}
  </main>
</SidebarProvider>
// components/app-sidebar.tsx
import {
  Sidebar, SidebarContent, SidebarGroup, SidebarMenu,
  SidebarMenuButton, SidebarMenuItem,
} from "@/components/ui/sidebar";
import { Home, Settings } from "lucide-react";

export function AppSidebar() {
  return (
    <Sidebar>
      <SidebarContent>
        <SidebarGroup>
          <SidebarMenu>
            <SidebarMenuItem>
              <SidebarMenuButton asChild>
                <a href="/"><Home /><span>首页</span></a>
              </SidebarMenuButton>
            </SidebarMenuItem>
            <SidebarMenuItem>
              <SidebarMenuButton asChild>
                <a href="/settings"><Settings /><span>设置</span></a>
              </SidebarMenuButton>
            </SidebarMenuItem>
          </SidebarMenu>
        </SidebarGroup>
      </SidebarContent>
    </Sidebar>
  );
}
Sidebar 自带的贴心

移动端自动降级为 Sheet 抽屉;折叠状态存 cookie 持久化;默认 Ctrl/Cmd + B 快捷键切换。这些都是拉进来的代码里现成的,可自行调整。

6.8 响应式布局套路

// Tailwind 断点:sm md lg xl 2xl
<div className="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-4">
  <Card>...</Card> <Card>...</Card>
</div>

// 桌面显示 Sidebar,移动端用 Sheet
<div className="hidden md:block"><AppSidebar /></div>
<div className="md:hidden"><MobileSheetNav /></div>

6.9 组件选择对照

需求
内容分块容器Card
同页多视图切换Tabs
可折叠的分组信息 / FAQAccordion
移动端菜单 / 临时侧面板Sheet
应用级持久侧边导航Sidebar
视觉分隔Separator

6.10 小结与下一步