Skip to content

Commit 84c8fb0

Browse files
jinmao88likui628
andauthored
feat: add support for custom slot header-index, sorted by index (vbenjs#4039)
* feat: header右侧支持n个自定义位置插槽,插槽命名方式header-index,根据index大小排序。 框架默认插槽user-dropdown的index:20,notification的index:10 (vbenjs#4034) * chore: 将默认组件加入排序 * chore: 更改slot命名方式支持header左侧自定义插槽,命名方式:header-right-n,header-left-n,具体位置看README --------- Co-authored-by: likui628 <[email protected]>
1 parent e27be2d commit 84c8fb0

File tree

3 files changed

+104
-16
lines changed

3 files changed

+104
-16
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## layout
2+
3+
### header
4+
5+
- 支持N个自定义插槽,命名方式:header-right-n,header-left-n
6+
- header-left-n ,排序方式:1-5 ,breadcrumb,6-x
7+
- header-right-n ,排序方式:1-4,global-search,6-9,theme-toggle,11-14,language-toggle,16-19,fullscreen,21-24,notification,26-29,user-dropdown,30-x

packages/effects/layouts/src/basic/header/header.vue

+87-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<script lang="ts" setup>
2+
import { computed, useSlots } from 'vue';
3+
24
import { preferences, usePreferences } from '@vben/preferences';
35
import { useAccessStore } from '@vben/stores';
46
import { VbenFullScreen } from '@vben-core/shadcn-ui';
@@ -22,26 +24,100 @@ withDefaults(defineProps<Props>(), {
2224
2325
const accessStore = useAccessStore();
2426
const { globalSearchShortcutKey } = usePreferences();
27+
const slots = useSlots();
28+
const rightSlots = computed(() => {
29+
const list = [{ index: 30, name: 'user-dropdown' }];
30+
if (preferences.widget.globalSearch) {
31+
list.push({
32+
index: 5,
33+
name: 'global-search',
34+
});
35+
}
36+
if (preferences.widget.themeToggle) {
37+
list.push({
38+
index: 10,
39+
name: 'theme-toggle',
40+
});
41+
}
42+
if (preferences.widget.languageToggle) {
43+
list.push({
44+
index: 15,
45+
name: 'language-toggle',
46+
});
47+
}
48+
if (preferences.widget.fullscreen) {
49+
list.push({
50+
index: 20,
51+
name: 'fullscreen',
52+
});
53+
}
54+
if (preferences.widget.notification) {
55+
list.push({
56+
index: 25,
57+
name: 'notification',
58+
});
59+
}
60+
61+
Object.keys(slots).forEach((key) => {
62+
const name = key.split('-');
63+
if (key.startsWith('header-right')) {
64+
list.push({ index: Number(name[2]), name: key });
65+
}
66+
});
67+
return list.sort((a, b) => a.index - b.index);
68+
});
69+
const leftSlots = computed(() => {
70+
const list: any[] = [];
71+
72+
Object.keys(slots).forEach((key) => {
73+
const name = key.split('-');
74+
if (key.startsWith('header-left')) {
75+
list.push({ index: Number(name[2]), name: key });
76+
}
77+
});
78+
return list.sort((a, b) => a.index - b.index);
79+
});
2580
</script>
2681

2782
<template>
83+
<template
84+
v-for="slot in leftSlots.filter((item) => item.index < 5)"
85+
:key="slot.name"
86+
>
87+
<slot :name="slot.name"></slot>
88+
</template>
2889
<div class="flex-center hidden lg:block">
2990
<slot name="breadcrumb"></slot>
3091
</div>
92+
<template
93+
v-for="slot in leftSlots.filter((item) => item.index > 5)"
94+
:key="slot.name"
95+
>
96+
<slot :name="slot.name"></slot>
97+
</template>
3198
<div class="flex h-full min-w-0 flex-1 items-center">
3299
<slot name="menu"></slot>
33100
</div>
34101
<div class="flex h-full min-w-0 flex-shrink-0 items-center">
35-
<GlobalSearch
36-
v-if="preferences.widget.globalSearch"
37-
:enable-shortcut-key="globalSearchShortcutKey"
38-
:menus="accessStore.accessMenus"
39-
class="mr-4"
40-
/>
41-
<ThemeToggle v-if="preferences.widget.themeToggle" class="mr-2" />
42-
<LanguageToggle v-if="preferences.widget.languageToggle" class="mr-2" />
43-
<VbenFullScreen v-if="preferences.widget.fullscreen" class="mr-2" />
44-
<slot v-if="preferences.widget.notification" name="notification"></slot>
45-
<slot name="user-dropdown"></slot>
102+
<template v-for="slot in rightSlots" :key="slot.name">
103+
<slot :name="slot.name">
104+
<template v-if="slot.name === 'global-search'">
105+
<GlobalSearch
106+
:enable-shortcut-key="globalSearchShortcutKey"
107+
:menus="accessStore.accessMenus"
108+
class="mr-4"
109+
/>
110+
</template>
111+
<template v-else-if="slot.name === 'theme-toggle'">
112+
<ThemeToggle class="mr-2" />
113+
</template>
114+
<template v-else-if="slot.name === 'language-toggle'">
115+
<LanguageToggle class="mr-2" />
116+
</template>
117+
<template v-else-if="slot.name === 'fullscreen'">
118+
<VbenFullScreen class="mr-2" />
119+
</template>
120+
</slot>
121+
</template>
46122
</div>
47123
</template>

packages/effects/layouts/src/basic/layout.vue

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script lang="ts" setup>
22
import type { MenuRecordRaw } from '@vben/types';
33
4-
import { computed, watch } from 'vue';
4+
import { computed, useSlots, watch } from 'vue';
55
66
import { useWatermark } from '@vben/hooks';
77
import { $t } from '@vben/locales';
@@ -136,18 +136,20 @@ watch(
136136
() => preferences.app.watermark,
137137
async (val) => {
138138
if (val) {
139-
// await nextTick();
140-
141-
updateWatermark({
139+
await updateWatermark({
142140
content: `${preferences.app.name} 用户名: ${userStore.userInfo?.username}`,
143-
// parent: contentRef.value,
144141
});
145142
}
146143
},
147144
{
148145
immediate: true,
149146
},
150147
);
148+
149+
const slots = useSlots();
150+
const headerSlots = computed(() => {
151+
return Object.keys(slots).filter((key) => key.startsWith('header-'));
152+
});
151153
</script>
152154

153155
<template>
@@ -240,6 +242,9 @@ watch(
240242
<template #notification>
241243
<slot name="notification"></slot>
242244
</template>
245+
<template v-for="item in headerSlots" #[item]>
246+
<slot :name="item"></slot>
247+
</template>
243248
</LayoutHeader>
244249
</template>
245250
<!-- 侧边菜单区域 -->

0 commit comments

Comments
 (0)