feat(projects): 支持同一路由根据不同query和hash同时显示不同Tab

ISSUES CLOSED: #64
This commit is contained in:
Soybean
2022-06-07 00:56:25 +08:00
parent 434ab1c560
commit 4122685803
20 changed files with 364 additions and 89 deletions

View File

@ -1,13 +1,15 @@
import type { RouteRecordNormalized, RouteLocationNormalizedLoaded } from 'vue-router';
/**
* 根据vue路由获取tab路由
* 根据vue路由获取tab路由
* @param route
*/
export function getTabRouteByVueRoute(route: RouteRecordNormalized | RouteLocationNormalizedLoaded) {
const fullPath = hasFullPath(route) ? route.fullPath : route.path;
const tabRoute: GlobalTabRoute = {
name: route.name,
path: route.path,
fullPath,
meta: route.meta,
scrollPosition: {
left: 0,
@ -20,17 +22,36 @@ export function getTabRouteByVueRoute(route: RouteRecordNormalized | RouteLocati
/**
* 获取该页签在多页签数据中的索引
* @param tabs - 多页签数据
* @param path - 该页签的路径
* @param fullPath - 该页签的路径
*/
export function getIndexInTabRoutes(tabs: GlobalTabRoute[], path: string) {
return tabs.findIndex(tab => tab.path === path);
export function getIndexInTabRoutes(tabs: GlobalTabRoute[], fullPath: string) {
return tabs.findIndex(tab => tab.fullPath === fullPath);
}
/**
* 判断该页签是否在多页签数据中
* @param tabs - 多页签数据
* @param path - 该页签的路径
* @param fullPath - 该页签的路径
*/
export function isInTabRoutes(tabs: GlobalTabRoute[], path: string) {
return getIndexInTabRoutes(tabs, path) > -1;
export function isInTabRoutes(tabs: GlobalTabRoute[], fullPath: string) {
return getIndexInTabRoutes(tabs, fullPath) > -1;
}
/**
* 根据路由名称获取该页签在多页签数据中的索引
* @param tabs - 多页签数据
* @param routeName - 路由名称
*/
export function getIndexInTabRoutesByRouteName(tabs: GlobalTabRoute[], routeName: string) {
return tabs.findIndex(tab => tab.name === routeName);
}
/**
* 判断路由是否有fullPath属性
* @param route 路由
*/
function hasFullPath(
route: RouteRecordNormalized | RouteLocationNormalizedLoaded
): route is RouteLocationNormalizedLoaded {
return Boolean((route as RouteLocationNormalizedLoaded).fullPath);
}

View File

@ -3,14 +3,14 @@ import { defineStore } from 'pinia';
import { useRouterPush } from '@/composables';
import { getTabRoutes, clearTabRoutes } from '@/utils';
import { useThemeStore } from '../theme';
import { getTabRouteByVueRoute, isInTabRoutes, getIndexInTabRoutes } from './helpers';
import { getTabRouteByVueRoute, isInTabRoutes, getIndexInTabRoutes, getIndexInTabRoutesByRouteName } from './helpers';
interface TabState {
/** 多页签数据 */
tabs: GlobalTabRoute[];
/** 多页签首页 */
homeTab: GlobalTabRoute;
/** 当前激活状态的页签(路由path) */
/** 当前激活状态的页签(路由fullPath) */
activeTab: string;
}
@ -19,7 +19,7 @@ export const useTabStore = defineStore('tab-store', {
tabs: [],
homeTab: {
name: 'root',
path: '/',
fullPath: '/',
meta: {
title: 'Root'
},
@ -34,7 +34,7 @@ export const useTabStore = defineStore('tab-store', {
/** 当前激活状态的页签索引 */
activeTabIndex(state) {
const { tabs, activeTab } = state;
return tabs.findIndex(tab => tab.path === activeTab);
return tabs.findIndex(tab => tab.fullPath === activeTab);
}
},
actions: {
@ -45,10 +45,10 @@ export const useTabStore = defineStore('tab-store', {
},
/**
* 设置当前路由对应的页签为激活状态
* @param path - 路由path
* @param fullPath - 路由fullPath
*/
setActiveTab(path: string) {
this.activeTab = path;
setActiveTab(fullPath: string) {
this.activeTab = fullPath;
},
/**
* 初始化首页页签路由
@ -68,23 +68,39 @@ export const useTabStore = defineStore('tab-store', {
* @param route - 路由
*/
addTab(route: RouteLocationNormalizedLoaded) {
if (!isInTabRoutes(this.tabs, route.path)) {
const tab = getTabRouteByVueRoute(route);
this.tabs.push(tab);
const tab = getTabRouteByVueRoute(route);
if (isInTabRoutes(this.tabs, tab.fullPath)) {
return;
}
const index = getIndexInTabRoutesByRouteName(this.tabs, route.name as string);
if (index === -1) {
this.tabs.push(tab);
return;
}
const { multiTab = false } = route.meta;
if (!multiTab) {
this.tabs.splice(index, 1, tab);
return;
}
this.tabs.push(tab);
},
/**
* 删除多页签
* @param path - 路由path
* @param fullPath - 路由fullPath
*/
removeTab(path: string) {
removeTab(fullPath: string) {
const { routerPush } = useRouterPush(false);
const isActive = this.activeTab === path;
const updateTabs = this.tabs.filter(tab => tab.path !== path);
const isActive = this.activeTab === fullPath;
const updateTabs = this.tabs.filter(tab => tab.fullPath !== fullPath);
this.tabs = updateTabs;
if (isActive && updateTabs.length) {
const activePath = updateTabs[updateTabs.length - 1].path;
const activePath = updateTabs[updateTabs.length - 1].fullPath;
this.setActiveTab(activePath);
routerPush(activePath);
}
@ -96,73 +112,73 @@ export const useTabStore = defineStore('tab-store', {
clearTab(excludes: string[] = []) {
const { routerPush } = useRouterPush(false);
const homePath = this.homeTab.path;
const homePath = this.homeTab.fullPath;
const remain = [homePath, ...excludes];
const hasActive = remain.includes(this.activeTab);
const updateTabs = this.tabs.filter(tab => remain.includes(tab.path));
const updateTabs = this.tabs.filter(tab => remain.includes(tab.fullPath));
this.tabs = updateTabs;
if (!hasActive && updateTabs.length) {
const activePath = updateTabs[updateTabs.length - 1].path;
const activePath = updateTabs[updateTabs.length - 1].fullPath;
this.setActiveTab(activePath);
routerPush(activePath);
}
},
/**
* 清除左边多页签
* @param path - 路由path
* @param fullPath - 路由fullPath
*/
clearLeftTab(path: string) {
const index = getIndexInTabRoutes(this.tabs, path);
clearLeftTab(fullPath: string) {
const index = getIndexInTabRoutes(this.tabs, fullPath);
if (index > -1) {
const excludes = this.tabs.slice(index).map(item => item.path);
const excludes = this.tabs.slice(index).map(item => item.fullPath);
this.clearTab(excludes);
}
},
/**
* 清除右边多页签
* @param path - 路由path
* @param fullPath - 路由fullPath
*/
clearRightTab(path: string) {
const index = getIndexInTabRoutes(this.tabs, path);
clearRightTab(fullPath: string) {
const index = getIndexInTabRoutes(this.tabs, fullPath);
if (index > -1) {
const excludes = this.tabs.slice(0, index + 1).map(item => item.path);
const excludes = this.tabs.slice(0, index + 1).map(item => item.fullPath);
this.clearTab(excludes);
}
},
/**
* 点击单个tab
* @param path - 路由path
* @param fullPath - 路由fullPath
*/
handleClickTab(path: string) {
handleClickTab(fullPath: string) {
const { routerPush } = useRouterPush(false);
const isActive = this.activeTab === path;
const isActive = this.activeTab === fullPath;
if (!isActive) {
this.setActiveTab(path);
routerPush(path);
this.setActiveTab(fullPath);
routerPush(fullPath);
}
},
/**
* 记录tab滚动位置
* @param path - 路由path
* @param fullPath - 路由fullPath
* @param position - tab当前页的滚动位置
*/
recordTabScrollPosition(path: string, position: { left: number; top: number }) {
const index = getIndexInTabRoutes(this.tabs, path);
recordTabScrollPosition(fullPath: string, position: { left: number; top: number }) {
const index = getIndexInTabRoutes(this.tabs, fullPath);
if (index > -1) {
this.tabs[index].scrollPosition = position;
}
},
/**
* 获取tab滚动位置
* @param path - 路由path
* @param fullPath - 路由fullPath
*/
getTabScrollPosition(path: string) {
getTabScrollPosition(fullPath: string) {
const position = {
left: 0,
top: 0
};
const index = getIndexInTabRoutes(this.tabs, path);
const index = getIndexInTabRoutes(this.tabs, fullPath);
if (index > -1) {
Object.assign(position, this.tabs[index].scrollPosition);
}
@ -174,20 +190,27 @@ export const useTabStore = defineStore('tab-store', {
const tabs: GlobalTabRoute[] = theme.tab.isCache ? getTabRoutes() : [];
const hasHome = isInTabRoutes(tabs, this.homeTab.path);
const hasHome = getIndexInTabRoutesByRouteName(tabs, this.homeTab.name as string) > -1;
if (!hasHome && this.homeTab.name !== 'root') {
tabs.unshift(this.homeTab);
}
const isHome = currentRoute.path === this.homeTab.path;
const hasCurrent = isInTabRoutes(tabs, currentRoute.path);
if (!isHome && !hasCurrent) {
const isHome = currentRoute.fullPath === this.homeTab.fullPath;
const index = getIndexInTabRoutesByRouteName(tabs, currentRoute.name as string);
if (!isHome) {
const currentTab = getTabRouteByVueRoute(currentRoute);
tabs.push(currentTab);
if (!currentRoute.meta.multiTab) {
tabs.splice(index, 1, currentTab);
} else {
const hasCurrent = isInTabRoutes(tabs, currentRoute.fullPath);
if (!hasCurrent) {
tabs.push(currentTab);
}
}
}
this.tabs = tabs;
this.setActiveTab(currentRoute.path);
this.setActiveTab(currentRoute.fullPath);
}
}
});