mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-01-23 01:30:26 +08:00
feat: add 'maxNumOfOpenTab' to limit the maximum number of tabs with the same name
This commit is contained in:
parent
bcd5e49117
commit
480580f104
@ -38,7 +38,8 @@
|
||||
"title": "Features",
|
||||
"hideChildrenInMenu": "Hide Menu Children",
|
||||
"loginExpired": "Login Expired",
|
||||
"tabs": "Tabs"
|
||||
"tabs": "Tabs",
|
||||
"tabDetail": "Tab Detail Page"
|
||||
},
|
||||
"breadcrumb": {
|
||||
"navigation": "Breadcrumb Navigation",
|
||||
|
@ -40,7 +40,8 @@
|
||||
"title": "功能",
|
||||
"hideChildrenInMenu": "隐藏子菜单",
|
||||
"loginExpired": "登录过期",
|
||||
"tabs": "标签页"
|
||||
"tabs": "标签页",
|
||||
"tabDetail": "标签详情页"
|
||||
},
|
||||
"breadcrumb": {
|
||||
"navigation": "面包屑导航",
|
||||
|
@ -107,6 +107,18 @@ const routes: RouteRecordRaw[] = [
|
||||
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',
|
||||
path: 'hide-menu-children',
|
||||
|
@ -28,6 +28,11 @@ function openTab() {
|
||||
router.push({ name: 'VbenAbout' });
|
||||
}
|
||||
|
||||
function openTabWithParams(id: number) {
|
||||
// 这里就是路由跳转,也可以用path
|
||||
router.push({ name: 'FeatureTabDetailDemo', params: { id } });
|
||||
}
|
||||
|
||||
function reset() {
|
||||
newTabTitle.value = '';
|
||||
resetTabTitle();
|
||||
@ -92,5 +97,19 @@ function reset() {
|
||||
<Button @click="reset"> 重置 </Button>
|
||||
</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>
|
||||
</template>
|
||||
|
29
apps/web-antd/src/views/demos/features/tabs/tab-detail.vue
Normal file
29
apps/web-antd/src/views/demos/features/tabs/tab-detail.vue
Normal 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>
|
@ -121,6 +121,7 @@ const customConfig: Linter.FlatConfig[] = [
|
||||
files: ['apps/backend-mock/**/**'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-extraneous-class': 'off',
|
||||
'n/no-extraneous-import': 'off',
|
||||
'n/prefer-global/buffer': 'off',
|
||||
'no-console': 'off',
|
||||
'unicorn/prefer-module': 'off',
|
||||
|
@ -100,6 +100,23 @@ const useCoreTabbarStore = defineStore('core-tabbar', {
|
||||
});
|
||||
|
||||
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);
|
||||
} else {
|
||||
// 页面已经存在,不重复添加选项卡,只更新选项卡参数
|
||||
|
@ -85,6 +85,11 @@ interface RouteMeta {
|
||||
* 路由是否已经加载过
|
||||
*/
|
||||
loaded?: boolean;
|
||||
/**
|
||||
* 标签页最大打开数量
|
||||
* @default false
|
||||
*/
|
||||
maxNumOfOpenTab?: number;
|
||||
/**
|
||||
* 菜单可以看到,但是访问会被重定向到403
|
||||
*/
|
||||
|
@ -50,7 +50,7 @@ export function useTabbar() {
|
||||
toggleTabPin,
|
||||
} = useTabs();
|
||||
const currentActive = computed(() => {
|
||||
return route.path;
|
||||
return route.fullPath;
|
||||
});
|
||||
|
||||
const { locale } = useI18n();
|
||||
|
@ -18,6 +18,10 @@
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["dist/**"]
|
||||
},
|
||||
"@vben/backend-mock#build": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": [".nitro/**", ".output/**"]
|
||||
},
|
||||
"stub": {},
|
||||
"dev": {
|
||||
"dependsOn": [],
|
||||
|
Loading…
Reference in New Issue
Block a user