| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 |
- import { ref, watch } from "vue";
- import type { Ref } from "vue";
- import type { RouteLocationNormalizedLoaded } from "vue-router";
- interface UseOpenedMenusOptions {
- route: RouteLocationNormalizedLoaded;
- accordion: Ref<boolean>;
- }
- export const useOpenedMenus = ({ route, accordion }: UseOpenedMenusOptions) => {
- const openedMenus = ref<string[]>([]);
- const stringify = (arr: string[]) => JSON.stringify([...arr].sort());
- const normalizePath = (path: string) => (path.startsWith("/") ? path : `/${path}`);
- const collectAncestorPaths = (path?: string) => {
- if (!path) return [];
- const normalized = normalizePath(path);
- const segments = normalized.split("/").filter(Boolean);
- return segments.reduce<string[]>((acc, _, index) => {
- if (index === segments.length - 1) return acc;
- acc.push(`/${segments.slice(0, index + 1).join("/")}`);
- return acc;
- }, []);
- };
- const buildTargetOpenedPaths = () => {
- const targetSet = new Set<string>();
- collectAncestorPaths(route.path).forEach(path => targetSet.add(path));
- const activeMenuPath = route.meta.activeMenu as string | undefined;
- if (activeMenuPath) {
- const normalizedActive = normalizePath(activeMenuPath);
- collectAncestorPaths(normalizedActive).forEach(path => targetSet.add(path));
- targetSet.add(normalizedActive);
- }
- return Array.from(targetSet);
- };
- const calculateOpenedMenus = () => {
- const targetPaths = buildTargetOpenedPaths();
- if (!targetPaths.length) {
- return accordion.value ? [] : [...openedMenus.value];
- }
- if (accordion.value) return targetPaths;
- const menuSet = new Set(openedMenus.value);
- targetPaths.forEach(path => menuSet.add(path));
- return Array.from(menuSet);
- };
- watch(
- () => [route.path, route.meta.activeMenu, accordion.value],
- () => {
- const newOpenedMenus = calculateOpenedMenus();
- if (stringify(newOpenedMenus) !== stringify(openedMenus.value)) {
- openedMenus.value = newOpenedMenus;
- }
- },
- { immediate: true }
- );
- return {
- openedMenus
- };
- };
|