Skip to content

Commit 28abcbf

Browse files
TsMasksendya
authored andcommitted
feat(pro-layout): 新增tab标签页自定义插槽
1 parent 80fe303 commit 28abcbf

File tree

4 files changed

+103
-13
lines changed

4 files changed

+103
-13
lines changed

Diff for: docs/components/pro-layout.md

+38-4
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,15 @@ const layoutConf = reactive({
118118
| menuHeaderRender | render header logo and title | v-slot \| VNode \| (logo,title)=>VNode \| false | - |
119119
| menuExtraRender | render extra menu item | v-slot \| VNode \| (props)=>VNode \| false | - |
120120
| menuFooterRender | render footer menu item | v-slot \| VNode \| (props)=>VNode \| false | - |
121-
| headerContentRender | custom header render method | `slot` \| (props: BasicLayoutProps) => VNode | - |
122-
| rightContentRender | header right content render method | `slot` \| (props: HeaderViewProps) => VNode | - |
121+
| menuItemRender | custom render Menu.Item | v-slot#menuItemRender="{ item, icon }" \| ({ item, icon }) => VNode | null |
122+
| subMenuItemRender | custom render Menu.SubItem | v-slot#subMenuItemRender="{ item, icon }" \| ({ item, icon }) => VNode | null |
123123
| collapsedButtonRender | custom collapsed button method | `slot` \| (collapsed: boolean) => VNode | - |
124+
| headerRender | custom header render method | `slot` \| (props: BasicLayoutProps) => VNode | - |
125+
| headerContentRender | header content render method only layout side | `slot` \| (props: BasicLayoutProps) => VNode | - |
126+
| rightContentRender | header right content render method | `slot` \| (props: BasicLayoutProps) => VNode | - |
124127
| footerRender | custom footer render method | `slot` \| (props: BasicLayoutProps) => VNode | `false` |
128+
| tabRender | custom tab render method | `slot` \| ({ width, ...BasicLayoutProps }) => VNode | `false` |
125129
| breadcrumbRender | custom breadcrumb render method | `slot` \| ({ route, params, routes, paths, h }) => VNode[] | - |
126-
| menuItemRender | custom render Menu.Item | v-slot#menuItemRender="{ item, icon }" \| ({ item, icon }) => VNode | null |
127-
| subMenuItemRender | custom render Menu.SubItem | v-slot#subMenuItemRender="{ item, icon }" \| ({ item, icon }) => VNode | null |
128130
| locale | i18n | Function (key: string) => string \| `false` | `false` |
129131

130132
> Menu generation requires `getMenuData` and `clearMenuItem` function
@@ -236,6 +238,38 @@ const layoutConf = reactive({
236238
</template>
237239
```
238240

241+
#### Custom tabRender
242+
243+
```vue
244+
<template #tabRender="{ width, fixedHeader }">
245+
<div>
246+
<header
247+
class="ant-layout-header"
248+
style="height: 36px; line-height: 36px; background: transparent"
249+
v-if="fixedHeader"
250+
></header>
251+
<div
252+
:style="{
253+
margin: '0',
254+
height: '36px',
255+
lineHeight: '36px',
256+
right: '0px',
257+
top: '48px',
258+
position: fixedHeader ? 'fixed' : 'unset',
259+
zIndex: 14,
260+
padding: '4px 16px',
261+
width: width,
262+
background: '#fff',
263+
boxShadow: '0 1px 4px #0015291f',
264+
transition: 'background 0.3s, width 0.2s',
265+
}"
266+
>
267+
tabRender fixedHeader:{{fixedHeader}} width:{{ width }}
268+
</div>
269+
</div>
270+
</template>
271+
```
272+
239273
#### Custom footer with slot
240274

241275
```vue

Diff for: packages/pro-layout/README.md

+38-4
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,15 @@ const layoutConf = reactive({
114114
| menuHeaderRender | render header logo and title | v-slot \| VNode \| (logo,title)=>VNode \| false | - |
115115
| menuExtraRender | render extra menu item | v-slot \| VNode \| (props)=>VNode \| false | - |
116116
| menuFooterRender | render footer menu item | v-slot \| VNode \| (props)=>VNode \| false | - |
117-
| headerContentRender | custom header render method | `slot` \| (props: BasicLayoutProps) => VNode | - |
118-
| rightContentRender | header right content render method | `slot` \| (props: HeaderViewProps) => VNode | - |
117+
| menuItemRender | custom render Menu.Item | v-slot#menuItemRender="{ item, icon }" \| ({ item, icon }) => VNode | null |
118+
| subMenuItemRender | custom render Menu.SubItem | v-slot#subMenuItemRender="{ item, icon }" \| ({ item, icon }) => VNode | null |
119119
| collapsedButtonRender | custom collapsed button method | `slot` \| (collapsed: boolean) => VNode | - |
120+
| headerRender | custom header render method | `slot` \| (props: BasicLayoutProps) => VNode | - |
121+
| headerContentRender | header content render method only layout side | `slot` \| (props: BasicLayoutProps) => VNode | - |
122+
| rightContentRender | header right content render method | `slot` \| (props: BasicLayoutProps) => VNode | - |
120123
| footerRender | custom footer render method | `slot` \| (props: BasicLayoutProps) => VNode | `false` |
124+
| tabRender | custom tab render method | `slot` \| ({ width, ...BasicLayoutProps }) => VNode | `false` |
121125
| breadcrumbRender | custom breadcrumb render method | `slot` \| ({ route, params, routes, paths, h }) => VNode[] | - |
122-
| menuItemRender | custom render Menu.Item | v-slot#menuItemRender="{ item, icon }" \| ({ item, icon }) => VNode | null |
123-
| subMenuItemRender | custom render Menu.SubItem | v-slot#subMenuItemRender="{ item, icon }" \| ({ item, icon }) => VNode | null |
124126
| locale | i18n | Function (key: string) => string \| `false` | `false` |
125127

126128
> Menu generation requires `getMenuData` and `clearMenuItem` function
@@ -232,6 +234,38 @@ const layoutConf = reactive({
232234
</template>
233235
```
234236

237+
#### Custom tabRender
238+
239+
```vue
240+
<template #tabRender="{ width, fixedHeader }">
241+
<div>
242+
<header
243+
class="ant-layout-header"
244+
style="height: 36px; line-height: 36px; background: transparent"
245+
v-if="fixedHeader"
246+
></header>
247+
<div
248+
:style="{
249+
margin: '0',
250+
height: '36px',
251+
lineHeight: '36px',
252+
right: '0px',
253+
top: '48px',
254+
position: fixedHeader ? 'fixed' : 'unset',
255+
zIndex: 14,
256+
padding: '4px 16px',
257+
width: width,
258+
background: '#fff',
259+
boxShadow: '0 1px 4px #0015291f',
260+
transition: 'background 0.3s, width 0.2s',
261+
}"
262+
>
263+
tabRender fixedHeader:{{fixedHeader}} width:{{ width }}
264+
</div>
265+
</div>
266+
</template>
267+
```
268+
235269
#### Custom footer with slot
236270

237271
```vue

Diff for: packages/pro-layout/src/BasicLayout.tsx

+26-5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import type {
3434
HeaderContentRender,
3535
HeaderRender,
3636
FooterRender,
37+
TabRender,
3738
RightContentRender,
3839
MenuItemRender,
3940
SubMenuItemRender,
@@ -99,9 +100,7 @@ export const basicLayoutProps = {
99100
},
100101
breadcrumbRender: {
101102
type: [Object, Function, Boolean] as PropType<BreadcrumbRender>,
102-
default() {
103-
return null;
104-
},
103+
default: () => null,
105104
},
106105
headerContentRender: {
107106
type: [Function, Object, Boolean] as PropType<HeaderContentRender>,
@@ -115,6 +114,10 @@ export const basicLayoutProps = {
115114
type: [Object, Function, Boolean] as PropType<FooterRender>,
116115
default: () => undefined,
117116
},
117+
tabRender: {
118+
type: [Object, Function, Boolean] as PropType<TabRender>,
119+
default: () => undefined,
120+
},
118121
};
119122

120123
export type BasicLayoutProps = Partial<ExtractPropTypes<typeof basicLayoutProps>>;
@@ -259,7 +262,8 @@ const ProLayout = defineComponent({
259262
const rightContentRender = getSlot<RightContentRender>(slots, props, 'rightContentRender');
260263
const customHeaderRender = getSlot<HeaderRender>(slots, props, 'headerRender');
261264
const footerRender = getSlot<FooterRender>(slots, props, 'footerRender');
262-
265+
const tabRender = getSlot<TabRender>(slots, props, 'tabRender');
266+
263267
// menu
264268
const menuHeaderRender = getSlot<MenuHeaderRender>(slots, props, 'menuHeaderRender');
265269
const menuExtraRender = getSlot<MenuExtraRender>(slots, props, 'menuExtraRender');
@@ -294,8 +298,24 @@ const ProLayout = defineComponent({
294298
)
295299
);
296300

301+
const tabDom = computed(() => {
302+
if (props.tabRender === false || !tabRender) {
303+
return null;
304+
}
305+
let layout = props.layout;
306+
let fixedHeader = props.fixedHeader;
307+
// 计算侧边栏的宽度,不然导致左边的样式会出问题
308+
let width = '100%';
309+
if (layout === 'mix' && hasSplitMenu.value && flatMenuData.value.length === 0) {
310+
width = '100%';
311+
} else if(fixedHeader && !isTop.value && !isMobile.value){
312+
width = `calc(100% - ${siderWidth.value}px)`;
313+
}
314+
return tabRender({ width, ...props });
315+
});
316+
297317
routeContext.hasHeader = !!headerDom.value;
298-
318+
299319
const contentClassName = computed(() => {
300320
return {
301321
[`${baseClassName.value}-content`]: true,
@@ -335,6 +355,7 @@ const ProLayout = defineComponent({
335355
)}
336356
<div style={genLayoutStyle} class={prefixCls.value}>
337357
{headerDom.value}
358+
{tabDom.value}
338359
<WrapContent
339360
isChildrenLayout={props.isChildrenLayout}
340361
class={contentClassName.value}

Diff for: packages/pro-layout/src/RenderTypings.ts

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export type BreadcrumbRender = BreadcrumbProps['itemRender'];
88
export type HeaderContentRender = WithFalse<() => CustomRender>;
99
export type HeaderRender = WithFalse<(props: ProProps) => CustomRender>;
1010
export type FooterRender = WithFalse<(props: ProProps) => CustomRender>;
11+
export type TabRender = WithFalse<(props: ProProps) => CustomRender>;
1112
export type RightContentRender = WithFalse<(props: ProProps) => CustomRender>;
1213
export type MenuItemRender = WithFalse<
1314
(args: { item: MenuDataItem; title?: JSX.Element; icon?: JSX.Element }) => CustomRender

0 commit comments

Comments
 (0)