mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-02-02 18:28:40 +08:00
feat: improve page
component (#5013)
* feat: `page` component support fixed header * docs: `page` component documentation * docs: Improve `props` types of `page` * docs: improve `fixedHeader` description of `page` * fix: `page` header border color with fixedHeader * feat: add `headerClass` for `Page`
This commit is contained in:
parent
24b9aa44d2
commit
17c7ce8f21
@ -148,6 +148,16 @@ function sidebarComponents(): DefaultTheme.SidebarItem[] {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
collapsed: false,
|
||||
text: '布局组件',
|
||||
items: [
|
||||
{
|
||||
link: 'layout-ui/page',
|
||||
text: 'Page 页面',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
collapsed: false,
|
||||
text: '通用组件',
|
||||
|
@ -6,6 +6,10 @@
|
||||
|
||||
:::
|
||||
|
||||
## 布局组件
|
||||
|
||||
布局组件一般在页面内容区域用作顶层容器组件,提供一些统一的布局样式和基本功能。
|
||||
|
||||
## 通用组件
|
||||
|
||||
通用组件是一些常用的组件,比如弹窗、抽屉、表单等。大部分基于 `Tailwind CSS` 实现,可适用于不同 UI 组件库的应用。
|
||||
|
45
docs/src/components/layout-ui/page.md
Normal file
45
docs/src/components/layout-ui/page.md
Normal file
@ -0,0 +1,45 @@
|
||||
---
|
||||
outline: deep
|
||||
---
|
||||
|
||||
# Page 常规页面组件
|
||||
|
||||
提供一个常规页面布局的组件,包括头部、内容区域、底部三个部分。
|
||||
|
||||
::: info 写在前面
|
||||
|
||||
本组件是一个基本布局组件。如果有更多的通用页面布局需求(比如双列布局等),可以根据实际需求自行封装。
|
||||
|
||||
:::
|
||||
|
||||
## 基础用法
|
||||
|
||||
将`Page`作为你的业务页面的根组件即可。
|
||||
|
||||
### Props
|
||||
|
||||
| 属性名 | 描述 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| title | 页面标题 | `string\|slot` | - |
|
||||
| description | 页面描述(标题下的内容) | `string\|slot` | - |
|
||||
| contentClass | 内容区域的class | `string` | - |
|
||||
| headerClass | 头部区域的class | `string` | - |
|
||||
| footerClass | 底部区域的class | `string` | - |
|
||||
| autoContentHeight | 自动调整内容区域的高度 | `boolean` | `false` |
|
||||
| fixedHeader | 固定头部在页面内容区域顶部,在滚动时保持可见 | `boolean` | `false` |
|
||||
|
||||
::: tip 注意
|
||||
|
||||
如果`title`、`description`、`extra`三者均未提供有效内容(通过`props`或者`slots`均可),则页面头部区域不会渲染。
|
||||
|
||||
:::
|
||||
|
||||
### Slots
|
||||
|
||||
| 插槽名称 | 描述 |
|
||||
| ----------- | ------------ |
|
||||
| default | 页面内容 |
|
||||
| title | 页面标题 |
|
||||
| description | 页面描述 |
|
||||
| extra | 页面头部右侧 |
|
||||
| footer | 页面底部 |
|
@ -503,7 +503,7 @@ function handleHeaderToggle() {
|
||||
|
||||
<div
|
||||
ref="contentRef"
|
||||
class="flex flex-1 flex-col overflow-hidden transition-all duration-300 ease-in"
|
||||
class="flex flex-1 flex-col transition-all duration-300 ease-in"
|
||||
>
|
||||
<div
|
||||
:class="[
|
||||
|
@ -22,6 +22,7 @@
|
||||
"dependencies": {
|
||||
"@vben-core/form-ui": "workspace:*",
|
||||
"@vben-core/popup-ui": "workspace:*",
|
||||
"@vben-core/preferences": "workspace:*",
|
||||
"@vben-core/shadcn-ui": "workspace:*",
|
||||
"@vben-core/shared": "workspace:*",
|
||||
"@vben/constants": "workspace:*",
|
||||
|
@ -1,5 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, ref, useTemplateRef } from 'vue';
|
||||
import {
|
||||
computed,
|
||||
nextTick,
|
||||
onMounted,
|
||||
ref,
|
||||
type StyleValue,
|
||||
useTemplateRef,
|
||||
} from 'vue';
|
||||
|
||||
import { preferences } from '@vben-core/preferences';
|
||||
import { cn } from '@vben-core/shared/utils';
|
||||
|
||||
interface Props {
|
||||
title?: string;
|
||||
@ -9,6 +19,10 @@ interface Props {
|
||||
* 根据content可见高度自适应
|
||||
*/
|
||||
autoContentHeight?: boolean;
|
||||
/** 头部固定 */
|
||||
fixedHeader?: boolean;
|
||||
headerClass?: string;
|
||||
footerClass?: string;
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
@ -20,6 +34,7 @@ const {
|
||||
description = '',
|
||||
autoContentHeight = false,
|
||||
title = '',
|
||||
fixedHeader = false,
|
||||
} = defineProps<Props>();
|
||||
|
||||
const headerHeight = ref(0);
|
||||
@ -29,6 +44,17 @@ const shouldAutoHeight = ref(false);
|
||||
const headerRef = useTemplateRef<HTMLDivElement>('headerRef');
|
||||
const footerRef = useTemplateRef<HTMLDivElement>('footerRef');
|
||||
|
||||
const headerStyle = computed<StyleValue>(() => {
|
||||
return fixedHeader
|
||||
? {
|
||||
position: 'sticky',
|
||||
zIndex: 200,
|
||||
top:
|
||||
preferences.header.mode === 'fixed' ? 'var(--vben-header-height)' : 0,
|
||||
}
|
||||
: undefined;
|
||||
});
|
||||
|
||||
const contentStyle = computed(() => {
|
||||
if (autoContentHeight) {
|
||||
return {
|
||||
@ -69,7 +95,14 @@ onMounted(() => {
|
||||
$slots.extra
|
||||
"
|
||||
ref="headerRef"
|
||||
class="bg-card relative px-6 py-4"
|
||||
:class="
|
||||
cn(
|
||||
'bg-card relative px-6 py-4',
|
||||
headerClass,
|
||||
fixedHeader ? 'border-border border-b' : '',
|
||||
)
|
||||
"
|
||||
:style="headerStyle"
|
||||
>
|
||||
<slot name="title">
|
||||
<div v-if="title" class="mb-2 flex text-lg font-semibold">
|
||||
@ -95,7 +128,12 @@ onMounted(() => {
|
||||
<div
|
||||
v-if="$slots.footer"
|
||||
ref="footerRef"
|
||||
class="bg-card align-center absolute bottom-0 left-0 right-0 flex px-6 py-4"
|
||||
:class="
|
||||
cn(
|
||||
footerClass,
|
||||
'bg-card align-center absolute bottom-0 left-0 right-0 flex px-6 py-4',
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot name="footer"></slot>
|
||||
</div>
|
||||
|
@ -1,13 +1,17 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
|
||||
import { Button, Card, message } from 'ant-design-vue';
|
||||
import { Button, Card, message, TabPane, Tabs } from 'ant-design-vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
|
||||
import DocButton from '../doc-button.vue';
|
||||
|
||||
const activeTab = ref('basic');
|
||||
|
||||
const [BaseForm, baseFormApi] = useVbenForm({
|
||||
// 所有表单项共用,可单独在表单内覆盖
|
||||
commonConfig: {
|
||||
@ -331,18 +335,31 @@ function handleSetFormValue() {
|
||||
<Page
|
||||
content-class="flex flex-col gap-4"
|
||||
description="表单组件基础示例,请注意,该页面用到的参数代码会添加一些简单注释,方便理解,请仔细查看。"
|
||||
fixed-header
|
||||
header-class="pb-0"
|
||||
title="表单组件"
|
||||
>
|
||||
<template #description>
|
||||
<div class="text-muted-foreground">
|
||||
<p>
|
||||
表单组件基础示例,请注意,该页面用到的参数代码会添加一些简单注释,方便理解,请仔细查看。
|
||||
</p>
|
||||
</div>
|
||||
<Tabs v-model:active-key="activeTab" :tab-bar-style="{ marginBottom: 0 }">
|
||||
<TabPane key="basic" tab="基础示例" />
|
||||
<TabPane key="layout" tab="自定义布局" />
|
||||
</Tabs>
|
||||
</template>
|
||||
<template #extra>
|
||||
<DocButton path="/components/common-ui/vben-form" />
|
||||
</template>
|
||||
<Card title="基础示例">
|
||||
<Card v-show="activeTab === 'basic'" title="基础示例">
|
||||
<template #extra>
|
||||
<Button type="primary" @click="handleSetFormValue">设置表单值</Button>
|
||||
</template>
|
||||
<BaseForm />
|
||||
</Card>
|
||||
<Card title="使用tailwind自定义布局">
|
||||
<Card v-show="activeTab === 'layout'" title="使用tailwind自定义布局">
|
||||
<CustomLayoutForm />
|
||||
</Card>
|
||||
</Page>
|
||||
|
@ -77,6 +77,7 @@ function openFormModal() {
|
||||
<template>
|
||||
<Page
|
||||
description="弹窗组件常用于在不离开当前页面的情况下,显示额外的信息、表单或操作提示,更多api请查看组件文档。"
|
||||
fixed-header
|
||||
title="弹窗组件示例"
|
||||
>
|
||||
<template #extra>
|
||||
|
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@ -1460,6 +1460,9 @@ importers:
|
||||
'@vben-core/popup-ui':
|
||||
specifier: workspace:*
|
||||
version: link:../../@core/ui-kit/popup-ui
|
||||
'@vben-core/preferences':
|
||||
specifier: workspace:*
|
||||
version: link:../../@core/preferences
|
||||
'@vben-core/shadcn-ui':
|
||||
specifier: workspace:*
|
||||
version: link:../../@core/ui-kit/shadcn-ui
|
||||
|
Loading…
Reference in New Issue
Block a user