Giao diện
CAppLayout
Khung shell của ứng dụng: dải logo, sidebar, header, vùng nội dung cuộn và chân trang.
Dùng khi: dự án cần layout khác hẳn mặc định và muốn dựng lại từ các mảnh có sẵn.
Không dùng khi: layout mặc định đủ dùng — layer đã lắp sẵn CAppLayout + CSideNav + CTopNav, dự án chỉ khai appTitle, nav, topNav trong app.config.ts. Xem Khung giao diện.
Các slot
┌──────────────┬────────────────────────────────────┐
│ #logo │ #header #actions │
├──────────────┼────────────────────────────────────┤
│ #nav │ (slot mặc định — nội dung trang) │
├──────────────┴────────────────────────────────────┤
│ #footer │
└───────────────────────────────────────────────────┘| Slot | Nội dung thường đặt |
|---|---|
#logo | Logo dự án; bỏ trống thì hiện app-title |
#nav | CSideNav |
#header | CTopNav hoặc breadcrumb toàn cục |
#actions | Chuông thông báo, nút đổi sáng/tối, menu tài khoản |
| mặc định | Nội dung trang |
#footer | Bỏ trống thì hiện footer-text |
Trạng thái thu gọn
vue
<CAppLayout v-model:collapsed="collapsed" />Sider rộng sider-width (mặc định 248px) khi mở và luôn 64px khi thu gọn. Trong app, layer giữ trạng thái ở useState('tasco:layout:collapsed') nên nó không bị mất khi chuyển trang.
Bỏ nút thu gọn ở dải logo bằng :collapsible="false".
Tự dựng layout cho dự án
vue
<!-- app/layouts/default.vue -->
<script setup lang="ts">
const appConfig = useAppConfig()
const route = useRoute()
const { filterByPermission } = usePermission()
const { isDark, toggle } = useThemeMode()
const collapsed = useState('tasco:layout:collapsed', () => false)
const nav = computed(() => filterByPermission(appConfig.tasco?.nav ?? []))
</script>
<template>
<CAppLayout
v-model:collapsed="collapsed"
:app-title="appConfig.tasco?.appTitle"
:footer-text="appConfig.tasco?.footerText"
>
<template #logo><img src="/logo.svg" alt="" height="28"></template>
<template #nav>
<CSideNav :items="nav" :active-path="route.path" :collapsed="collapsed" @navigate="navigateTo" />
</template>
<template #actions>
<CButton variant="text" size="sm" @click="toggle">
{{ isDark ? 'Sáng' : 'Tối' }}
</CButton>
</template>
<NuxtErrorBoundary>
<slot />
<template #error="{ error }">
<CEmpty :description="`Đã xảy ra lỗi: ${error?.message}`" bordered />
</template>
</NuxtErrorBoundary>
</CAppLayout>
</template>Ghi đè layout là nhận luôn trách nhiệm: lọc menu theo quyền, nút đổi sáng/tối, menu tài khoản và đăng xuất, và <NuxtErrorBoundary> quanh nội dung.
API
Props
| Tên | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
collapsed | boolean | false | v-model:collapsed — sider đang thu gọn hay không. |
appTitle | string | 'Tasco' | Tên ứng dụng hiện ở dải logo (khi không dùng slot #logo). |
footerText | string | '' | Chữ chân trang; rỗng và không có slot #footer thì ẩn chân trang. |
collapsible | boolean | true | Hiện nút thu gọn/mở sider ở dải logo. |
siderWidth | number | 248 | Bề rộng sider khi mở (px); lúc thu gọn luôn là 64px. |
Sự kiện
| Tên | Payload | Mô tả |
|---|---|---|
update:collapsed | [v: boolean] | v-model:collapsed — phát khi bấm nút thu gọn/mở sider. |
Slot
| Tên | Props của slot | Mô tả |
|---|---|---|
#logo | any | Logo ở dải navy góc trên trái; mặc định hiện `appTitle`. |
#header | any | Nội dung bên trái header, vd menu module ngang (CTopNav). |
#actions | any | Khu vực bên phải header: thông báo, tài khoản. |
#nav | any | Menu sider — thường là CSideNav. |
#default | any | Nội dung trang. |
#footer | any | Chân trang; mặc định hiện `footerText`. |
Khả năng tiếp cận
- Nút thu gọn có nhãn đọc màn hình sẵn; nút tự thêm vào
#actionsthì phải tự đặtaria-label. - Vùng nội dung cuộn riêng, header và sider đứng yên — người dùng bàn phím
Tabtừ header xuống nội dung theo thứ tự tự nhiên. - Giữ một
<h1>duy nhất cho mỗi trang, thường làCPageHeadertrong vùng nội dung.
Lưu ý
- Layout là một cho cả app: đừng lồng
CAppLayouttrong trang. - Nội dung trang tự lo khoảng đệm — layout không thêm padding vào slot mặc định.
- Màn hình hẹp: sider thu về dải icon, nội dung vẫn cuộn bình thường; bảng rộng thì cho cuộn ngang thay vì ép co.
Liên quan
CSideNav,CTopNav.- Khung giao diện — cách khai báo menu thay vì dựng tay.
- Layer cung cấp gì — ghi đè layout mặc định.