feat(web): 页头操作按钮独立成行——标题下 content 槽右侧对齐,关闭面包屑

This commit is contained in:
2026-09-24 17:10:28 +08:00
parent 27e167b8e5
commit 04bec3aa84
3 changed files with 12 additions and 14 deletions
+1 -1
View File
@@ -61,7 +61,7 @@
## UI 规范(antd/pro)
- 页面标题右侧的操作按钮与标题底部对齐(Layout 页头槽内联样式控制,勿在其他位置另造对齐方式)。
- 页面标题与操作按钮各占一行:标题用 PageContainer 自带 `title`/`subTitle`,按钮经 `usePageActions` 注册到 Layout 页头 content 槽(`Flex justify="flex-end"`),不写自定义对齐样式,勿在其他位置另造对齐方式。
- 页面级操作按钮通过 `usePageActions` 注册到页头槽,不得在卡片内重复渲染。
- 弃用 API 禁止回潮:`Alert` 用 `title`/`description`(非 `message`)、纵向堆叠用 `Flex vertical`(非 `Space direction`)、静态 `message.xxx` 改 `App.useApp()`。以 `antd lint` 结果为准。
+1 -1
View File
@@ -1,7 +1,7 @@
import { createContext, useContext, useEffect } from 'react';
import type { ReactNode } from 'react';
// 页头动作槽:页面挂载时把自己的操作按钮注册到布局 PageContainer 的 extra(与标题同一行),
// 页头动作槽:页面挂载时把自己的操作按钮注册到布局 PageContainer 的 content(标题下方独立操作行,右侧对齐),
// 卸载时自动清除。Layout 提供 Provider,页面只消费 usePageActions。
const PageActionsContext = createContext<(node: ReactNode) => void>(() => {});
+10 -12
View File
@@ -2,7 +2,7 @@ import { useState } from 'react';
import type { ReactNode } from 'react';
import { history, Outlet, useLocation } from '@umijs/max';
import { PageContainer, ProLayout } from '@ant-design/pro-components';
import { App, Dropdown, Typography } from 'antd';
import { App, Dropdown, Flex } from 'antd';
import { LogoutOutlined } from '@ant-design/icons';
import { PageActionsContext } from '@/components/PageActions';
import { menu, menuSelectedKey, pageMetadata } from '@/utils/metadata';
@@ -12,7 +12,7 @@ import { menu, menuSelectedKey, pageMetadata } from '@/utils/metadata';
// (渲染器不传 children prop,用 children 会导致整页空白且无任何报错)。
export default function Layout() {
const location = useLocation();
// 页头动作槽:列表页在挂载时把自己的添加类按钮注册进来,与标题渲染在同一行。
// 页头动作槽:列表页在挂载时把自己的添加类按钮注册进来,渲染在标题下方的独立操作行(右侧)。
const [pageActions, setPageActions] = useState<ReactNode>(null);
if (location.pathname === '/login') return <Outlet />;
@@ -58,20 +58,18 @@ export default function Layout() {
),
}}
>
{/* 页面标题在卡片外(内容区左上角),动作按钮与标题同一行(右侧);卡片内不再重复渲染标题。 */}
{/* 页面标题在卡片外(内容区左上角),动作按钮单独一行渲染在标题下方(content 槽,右侧对齐);卡片内不再重复渲染标题。 */}
{/* App 包裹:App.useApp() 的 message 等实例需要此上下文(component=false 不增加 DOM,避免破坏 ProLayout 布局)。 */}
<App component={false}>
<PageContainer
ghost
title={
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'flex-end', height: '100%' }}>
<Typography.Title level={4} style={{ marginBottom: 2 }}>{meta.title}</Typography.Title>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>{meta.subtitle}</Typography.Text>
</div>
}
subTitle={false}
// 官方 skill 规范:标题右侧操作按钮底部对齐(PageContainer 的 -row 未设 align-items,默认居中)。
extra={<div style={{ alignSelf: 'flex-end' }}>{pageActions}</div>}
title={meta.title}
subTitle={meta.subtitle}
// 全站不展示面包屑导航(官方关闭方式:breadcrumbRender={false})。
breadcrumbRender={false}
// 标题与操作按钮各占一行:标题走 PageContainer 自带 title/subTitle,按钮走 content 槽,
// 右对齐用 Flex 组件 API,不写自定义对齐样式。
content={pageActions ? <Flex justify="flex-end">{pageActions}</Flex> : undefined}
>
<Outlet />
</PageContainer>