AppShell 应用脚手架
header + sidebar + main + aside + footer 的 CSS Grid 布局,整站脚手架推荐起点。
基础用法
AppShell 把整个应用最常见的几块布局区域固定下来:顶部头栏(sticky)、左侧栏、可选的右侧栏、主区域、底栏。每一块都是命名 slot / prop,留空则不渲染。
侧栏宽度通过 sidebarWidth(数字,px)控制;sidebarCollapsed=true 把侧栏宽度收成 0 但保留 DOM,便于响应式切换。
背景
<script setup lang="ts">
import { ref } from 'vue';
import { CfAppShell, CfButton } from '@chufix-design/vue';
const collapsed = ref(false);
</script>
<template>
<div style="height: 360px; border: 1px solid var(--line-1); border-radius: 8px; overflow: hidden;">
<CfAppShell :sidebar-collapsed="collapsed" :sidebar-width="180">
<template #header>
<div style="display:flex; align-items:center; gap: 12px; width: 100%;">
<CfButton size="sm" variant="tertiary" @click="collapsed = !collapsed">
{{ collapsed ? '展开侧栏' : '收起侧栏' }}
</CfButton>
<strong style="margin-right:auto;">My App</strong>
<span style="font-size: 12px; color: var(--fg-3);">user@example.com</span>
</div>
</template>
<template #sidebar>
<nav style="padding: 12px;">
<div style="font-size: 11px; color: var(--fg-3); padding: 0 8px 6px;">导航</div>
<a href="#" style="display:block; padding: 6px 8px; border-radius: 4px; background: var(--accent-soft); color: var(--accent-1); font-size: 13px;">概览</a>
<a href="#" style="display:block; padding: 6px 8px; border-radius: 4px; color: var(--fg-2); font-size: 13px;">分析</a>
<a href="#" style="display:block; padding: 6px 8px; border-radius: 4px; color: var(--fg-2); font-size: 13px;">订单</a>
<a href="#" style="display:block; padding: 6px 8px; border-radius: 4px; color: var(--fg-2); font-size: 13px;">用户</a>
<a href="#" style="display:block; padding: 6px 8px; border-radius: 4px; color: var(--fg-2); font-size: 13px;">设置</a>
</nav>
</template>
<template #footer>
© ChuFix · v0.0.1
</template>
<div style="padding: 24px;">
<h2 style="margin: 0 0 6px; font-size: 18px;">主区域</h2>
<p style="margin: 0; color: var(--fg-2);">点击左上角按钮可以收起 / 展开侧栏。</p>
</div>
</CfAppShell>
</div>
</template> <script setup>
import { ref } from 'vue';
import { CfAppShell, CfButton } from '@chufix-design/vue';
const collapsed = ref(false);
</script>
<template>
<div style="height: 360px; border: 1px solid var(--line-1); border-radius: 8px; overflow: hidden;">
<CfAppShell :sidebar-collapsed="collapsed" :sidebar-width="180">
<template #header>
<div style="display:flex; align-items:center; gap: 12px; width: 100%;">
<CfButton size="sm" variant="tertiary" @click="collapsed = !collapsed">
{{ collapsed ? '展开侧栏' : '收起侧栏' }}
</CfButton>
<strong style="margin-right:auto;">My App</strong>
<span style="font-size: 12px; color: var(--fg-3);">user@example.com</span>
</div>
</template>
<template #sidebar>
<nav style="padding: 12px;">
<div style="font-size: 11px; color: var(--fg-3); padding: 0 8px 6px;">导航</div>
<a href="#" style="display:block; padding: 6px 8px; border-radius: 4px; background: var(--accent-soft); color: var(--accent-1); font-size: 13px;">概览</a>
<a href="#" style="display:block; padding: 6px 8px; border-radius: 4px; color: var(--fg-2); font-size: 13px;">分析</a>
<a href="#" style="display:block; padding: 6px 8px; border-radius: 4px; color: var(--fg-2); font-size: 13px;">订单</a>
<a href="#" style="display:block; padding: 6px 8px; border-radius: 4px; color: var(--fg-2); font-size: 13px;">用户</a>
<a href="#" style="display:block; padding: 6px 8px; border-radius: 4px; color: var(--fg-2); font-size: 13px;">设置</a>
</nav>
</template>
<template #footer>
© ChuFix · v0.0.1
</template>
<div style="padding: 24px;">
<h2 style="margin: 0 0 6px; font-size: 18px;">主区域</h2>
<p style="margin: 0; color: var(--fg-2);">点击左上角按钮可以收起 / 展开侧栏。</p>
</div>
</CfAppShell>
</div>
</template> import { useState } from 'react';
import { CfAppShell, CfButton } from '@chufix-design/react';
export default function Demo() {
const [collapsed, setCollapsed] = useState(false);
return (
<CfAppShell
sidebarCollapsed={collapsed}
sidebarWidth={180}
header={
<>
<CfButton size="sm" variant="tertiary" onClick={() => setCollapsed((v) => !v)}>
{collapsed ? '展开侧栏' : '收起侧栏'}
</CfButton>
<strong>My App</strong>
</>
}
sidebar={<nav>导航列表</nav>}
footer={<>© ChuFix</>}
>
<div>主区域内容</div>
</CfAppShell>
);
} import { useState } from 'react';
import { CfAppShell, CfButton } from '@chufix-design/react';
export default function Demo() {
const [collapsed, setCollapsed] = useState(false);
return (
<CfAppShell
sidebarCollapsed={collapsed}
sidebarWidth={180}
header={
<>
<CfButton size="sm" variant="tertiary" onClick={() => setCollapsed((v) => !v)}>
{collapsed ? '展开侧栏' : '收起侧栏'}
</CfButton>
<strong>My App</strong>
</>
}
sidebar={<nav>导航列表</nav>}
footer={<>© ChuFix</>}
>
<div>主区域内容</div>
</CfAppShell>
);
} 布局区域
┌──────────────────────────────────────────┐
│ header (sticky) │
├────────┬──────────────────┬──────────────┤
│ │ │ │
│ side- │ main │ aside │
│ bar │ │ (右侧栏) │
│ │ │ │
├────────┴──────────────────┴──────────────┤
│ footer │
└──────────────────────────────────────────┘
header默认position: sticky; top: 0,滚动主区域时保持悬挂sidebar/aside/main各自overflow-y: auto,互相独立滚动;都加了overscroll-behavior: contain防止滚动链式冒泡- 整体用
display: grid,布局区域由grid-template-areas定义
加上右侧栏 aside
aside slot 启用最右一列,常用于详情面板、大纲、提示侧栏。asideWidth 控制宽度。
背景
主内容区,左右两侧栏 + 顶底栏的完整脚手架。
<script setup lang="ts">
import { CfAppShell } from '@chufix-design/vue';
</script>
<template>
<CfAppShell :sidebar-width="160" :aside-width="200">
<template #header><strong>顶栏</strong></template>
<template #sidebar><nav>左侧导航</nav></template>
<template #aside>
<div style="padding: 8px;">右侧 aside — 详情 / 大纲 / 提示</div>
</template>
<template #footer>底栏</template>
<div style="padding: 12px;">主内容区,左右两侧栏 + 顶底栏的完整脚手架。</div>
</CfAppShell>
</template> <script setup>
import { CfAppShell } from '@chufix-design/vue';
</script>
<template>
<CfAppShell :sidebar-width="160" :aside-width="200">
<template #header><strong>顶栏</strong></template>
<template #sidebar><nav>左侧导航</nav></template>
<template #aside>
<div style="padding: 8px;">右侧 aside — 详情 / 大纲 / 提示</div>
</template>
<template #footer>底栏</template>
<div style="padding: 12px;">主内容区,左右两侧栏 + 顶底栏的完整脚手架。</div>
</CfAppShell>
</template> <CfAppShell
sidebarWidth={160}
asideWidth={200}
header={<>顶栏</>}
sidebar={<>左侧导航</>}
aside={<>右侧 aside</>}
footer={<>底栏</>}
>
<div>主内容区</div>
</CfAppShell> <CfAppShell
sidebarWidth={160}
asideWidth={200}
header={<>顶栏</>}
sidebar={<>左侧导航</>}
aside={<>右侧 aside</>}
footer={<>底栏</>}
>
<div>主内容区</div>
</CfAppShell> 三档密度 variant
variant 控制整体字号 / 内距档位 — default / condensed(紧凑后台用)/ spacious(落地页 / 大屏用)。
背景
variant = condensed
紧凑型 — 整体字号小一档
variant = spacious
宽松型 — 字号 / 内距大一档
<script setup lang="ts">
import { CfAppShell } from '@chufix-design/vue';
</script>
<template>
<div class="demo-stack">
<div>
<div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">variant = condensed</div>
<CfAppShell variant="condensed" :sidebar-width="140">
<template #header>condensed 顶栏</template>
<template #sidebar>侧栏</template>
<div style="padding: 8px;">紧凑型 — 整体字号小一档</div>
</CfAppShell>
</div>
<div>
<div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">variant = spacious</div>
<CfAppShell variant="spacious" :sidebar-width="160">
<template #header>spacious 顶栏</template>
<template #sidebar>侧栏</template>
<div style="padding: 12px;">宽松型 — 字号 / 内距大一档</div>
</CfAppShell>
</div>
</div>
</template> <script setup>
import { CfAppShell } from '@chufix-design/vue';
</script>
<template>
<div class="demo-stack">
<div>
<div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">variant = condensed</div>
<CfAppShell variant="condensed" :sidebar-width="140">
<template #header>condensed 顶栏</template>
<template #sidebar>侧栏</template>
<div style="padding: 8px;">紧凑型 — 整体字号小一档</div>
</CfAppShell>
</div>
<div>
<div style="font-size: 12px; color: var(--fg-3); margin-bottom: 4px;">variant = spacious</div>
<CfAppShell variant="spacious" :sidebar-width="160">
<template #header>spacious 顶栏</template>
<template #sidebar>侧栏</template>
<div style="padding: 12px;">宽松型 — 字号 / 内距大一档</div>
</CfAppShell>
</div>
</div>
</template> <CfAppShell variant="condensed">…</CfAppShell>
<CfAppShell variant="spacious">…</CfAppShell> <CfAppShell variant="condensed">…</CfAppShell>
<CfAppShell variant="spacious">…</CfAppShell> API
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
variant | 'default' | 'condensed' | 'spacious' | 'default' | 整体字号档位 |
sidebarWidth | number | 240 | 侧栏宽度(px) |
headerHeight | number | auto | 顶栏固定高度(px);省略时按内容自适应 |
bordered | boolean | true | 侧栏是否描右边框 |
sidebarCollapsed | boolean | false | 是否收起侧栏(视觉宽度归 0) |
Vue slot:header / sidebar / aside / footer / 默认(main)。
React 用同名 prop 接 ReactNode,主内容传 children。
反馈与讨论
AppShell 应用脚手架 的讨论