feat: add 'maxNumOfOpenTab' to limit the maximum number of tabs with the same name

This commit is contained in:
vben 2024-07-20 11:14:32 +08:00
parent bcd5e49117
commit 480580f104
10 changed files with 92 additions and 3 deletions

View File

@ -38,7 +38,8 @@
"title": "Features", "title": "Features",
"hideChildrenInMenu": "Hide Menu Children", "hideChildrenInMenu": "Hide Menu Children",
"loginExpired": "Login Expired", "loginExpired": "Login Expired",
"tabs": "Tabs" "tabs": "Tabs",
"tabDetail": "Tab Detail Page"
}, },
"breadcrumb": { "breadcrumb": {
"navigation": "Breadcrumb Navigation", "navigation": "Breadcrumb Navigation",

View File

@ -40,7 +40,8 @@
"title": "功能", "title": "功能",
"hideChildrenInMenu": "隐藏子菜单", "hideChildrenInMenu": "隐藏子菜单",
"loginExpired": "登录过期", "loginExpired": "登录过期",
"tabs": "标签页" "tabs": "标签页",
"tabDetail": "标签详情页"
}, },
"breadcrumb": { "breadcrumb": {
"navigation": "面包屑导航", "navigation": "面包屑导航",

View File

@ -107,6 +107,18 @@ const routes: RouteRecordRaw[] = [
title: $t('page.demos.features.tabs'), title: $t('page.demos.features.tabs'),
}, },
}, },
{
name: 'FeatureTabDetailDemo',
path: 'tabs/detail/:id',
component: () =>
import('#/views/demos/features/tabs/tab-detail.vue'),
meta: {
activePath: '/demos/features/tabs',
hideInMenu: true,
maxNumOfOpenTab: 3,
title: $t('page.demos.features.tabDetail'),
},
},
{ {
name: 'HideChildrenInMenuParent', name: 'HideChildrenInMenuParent',
path: 'hide-menu-children', path: 'hide-menu-children',

View File

@ -28,6 +28,11 @@ function openTab() {
router.push({ name: 'VbenAbout' }); router.push({ name: 'VbenAbout' });
} }
function openTabWithParams(id: number) {
// path
router.push({ name: 'FeatureTabDetailDemo', params: { id } });
}
function reset() { function reset() {
newTabTitle.value = ''; newTabTitle.value = '';
resetTabTitle(); resetTabTitle();
@ -92,5 +97,19 @@ function reset() {
<Button @click="reset"> 重置 </Button> <Button @click="reset"> 重置 </Button>
</div> </div>
</div> </div>
<div class="card-box mt-5 p-5">
<div class="text-lg font-semibold">最大打开数量</div>
<div class="text-foreground/80 my-3">
限制带参数的tab打开的最大数量 `route.meta.maxNumOfOpenTab` 控制
</div>
<div class="flex flex-wrap items-center gap-3">
<template v-for="item in 5" :key="item">
<Button type="primary" @click="openTabWithParams(item)">
打开{{ item }}详情页
</Button>
</template>
</div>
</div>
</div> </div>
</template> </template>

View File

@ -0,0 +1,29 @@
<script lang="ts" setup>
import { computed } from 'vue';
import { useRoute } from 'vue-router';
import { useTabs } from '@vben/hooks';
defineOptions({ name: 'FeatureTabDetailDemo' });
const route = useRoute();
const { setTabTitle } = useTabs();
const index = computed(() => {
return route.params?.id ?? -1;
});
setTabTitle(`No.${index.value} - 详情信息`);
</script>
<template>
<div class="p-5">
<div class="card-box p-5">
<h1 class="text-xl font-semibold">标签详情页</h1>
<div class="text-foreground/80 mt-2">
<div>{{ index }} - 详情页内容在此</div>
</div>
</div>
</div>
</template>

View File

@ -121,6 +121,7 @@ const customConfig: Linter.FlatConfig[] = [
files: ['apps/backend-mock/**/**'], files: ['apps/backend-mock/**/**'],
rules: { rules: {
'@typescript-eslint/no-extraneous-class': 'off', '@typescript-eslint/no-extraneous-class': 'off',
'n/no-extraneous-import': 'off',
'n/prefer-global/buffer': 'off', 'n/prefer-global/buffer': 'off',
'no-console': 'off', 'no-console': 'off',
'unicorn/prefer-module': 'off', 'unicorn/prefer-module': 'off',

View File

@ -100,6 +100,23 @@ const useCoreTabbarStore = defineStore('core-tabbar', {
}); });
if (tabIndex === -1) { if (tabIndex === -1) {
// 获取动态路由打开数,超过 0 即代表需要控制打开数
const maxNumOfOpenTab = (routeTab?.meta?.maxNumOfOpenTab ??
-1) as number;
// 如果动态路由层级大于 0 了,那么就要限制该路由的打开数限制了
// 获取到已经打开的动态路由数, 判断是否大于某一个值
if (
maxNumOfOpenTab > 0 &&
this.tabs.filter((tab) => tab.name === routeTab.name).length >=
maxNumOfOpenTab
) {
// 关闭第一个
const index = this.tabs.findIndex(
(item) => item.name === routeTab.name,
);
index !== -1 && this.tabs.splice(index, 1);
}
this.tabs.push(tab); this.tabs.push(tab);
} else { } else {
// 页面已经存在,不重复添加选项卡,只更新选项卡参数 // 页面已经存在,不重复添加选项卡,只更新选项卡参数

View File

@ -85,6 +85,11 @@ interface RouteMeta {
* *
*/ */
loaded?: boolean; loaded?: boolean;
/**
*
* @default false
*/
maxNumOfOpenTab?: number;
/** /**
* 访403 * 访403
*/ */

View File

@ -50,7 +50,7 @@ export function useTabbar() {
toggleTabPin, toggleTabPin,
} = useTabs(); } = useTabs();
const currentActive = computed(() => { const currentActive = computed(() => {
return route.path; return route.fullPath;
}); });
const { locale } = useI18n(); const { locale } = useI18n();

View File

@ -18,6 +18,10 @@
"dependsOn": ["^build"], "dependsOn": ["^build"],
"outputs": ["dist/**"] "outputs": ["dist/**"]
}, },
"@vben/backend-mock#build": {
"dependsOn": ["^build"],
"outputs": [".nitro/**", ".output/**"]
},
"stub": {}, "stub": {},
"dev": { "dev": {
"dependsOn": [], "dependsOn": [],