feat(router): 优化路由排序逻辑并添加菜单排序权重支持
This commit is contained in:
@@ -44,7 +44,42 @@ function convertRoutesToMenuOptions(routes: Readonly<RouteRecordRaw[]>): MenuOpt
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.sort((a, b) => a.path.localeCompare(b.path));
|
||||
// 排序路由,确保父路由总是在子路由之前,同级路由则根据 `meta.order` 排序
|
||||
.sort((a: RouteRecordRaw, b: RouteRecordRaw) => {
|
||||
const pathA = a.path;
|
||||
const pathB = b.path;
|
||||
const segmentsA = pathA.split('/').filter(Boolean);
|
||||
const segmentsB = pathB.split('/').filter(Boolean);
|
||||
const parentAPath = `/${segmentsA.slice(0, -1).join('/')}`;
|
||||
const parentBPath = `/${segmentsB.slice(0, -1).join('/')}`;
|
||||
|
||||
// 如果不是同级路由,则按路径排序,确保父路由在前
|
||||
if (parentAPath !== parentBPath) {
|
||||
return pathA.localeCompare(pathB);
|
||||
}
|
||||
|
||||
// 同级路由,处理 `meta.order`
|
||||
const orderA = a.meta?.order;
|
||||
const orderB = b.meta?.order;
|
||||
const hasOrderA = orderA !== undefined;
|
||||
const hasOrderB = orderB !== undefined;
|
||||
|
||||
// 当一个有 order 而另一个没有时,有 order 的排在前面
|
||||
if (hasOrderA !== hasOrderB) {
|
||||
return hasOrderA ? -1 : 1;
|
||||
}
|
||||
|
||||
// 当两个都有 order 时,按 order 值升序排序
|
||||
if (hasOrderA && hasOrderB) {
|
||||
const orderDiff = orderA - orderB;
|
||||
if (orderDiff !== 0) {
|
||||
return orderDiff;
|
||||
}
|
||||
}
|
||||
|
||||
// order 相同或都没有 order,按路径字母顺序排序
|
||||
return pathA.localeCompare(pathB);
|
||||
});
|
||||
|
||||
// 构建菜单树
|
||||
for (const route of validRoutes) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
definePage({
|
||||
meta: {},
|
||||
meta: {
|
||||
order: 1,
|
||||
},
|
||||
});
|
||||
const { t, locale } = useI18n();
|
||||
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
definePage({ meta: { link: !false } });
|
||||
definePage({
|
||||
meta: {
|
||||
link: !false,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<template><div>Demos</div></template>
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { autoAnimatePlugin } from '@formkit/auto-animate/vue';
|
||||
|
||||
export function install({ app }: { app: import('vue').App<Element> }) {
|
||||
app.config.globalProperties.__DEV__ = __DEV__;
|
||||
|
||||
app.use(autoAnimatePlugin); // v-auto-animate="{ duration: 100 }"
|
||||
|
||||
app.config.errorHandler = (error, instance, info) => {
|
||||
console.error('Global error:', error);
|
||||
console.error('Component:', instance);
|
||||
|
||||
@@ -43,8 +43,10 @@ declare module 'vue-router' {
|
||||
* @description 是否在菜单中隐藏
|
||||
*/
|
||||
hideInMenu?: boolean;
|
||||
|
||||
/**
|
||||
* @description 菜单标题
|
||||
* @deprecated //!⚠️请通过多语言标题方案(搜`PageTitleLocalizations`)维护标题
|
||||
*/
|
||||
title?: string;
|
||||
|
||||
@@ -59,6 +61,11 @@ declare module 'vue-router' {
|
||||
* - false: 仅渲染纯文本标签,不可点击(适用于分组标题)
|
||||
*/
|
||||
link?: boolean;
|
||||
|
||||
/**
|
||||
* @description 菜单排序权重,数值越小越靠前,未设置则按路径字母顺序排序
|
||||
*/
|
||||
order?: number;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user