同步导航菜单与路由,并在关闭标签(或浏览器)后重新时,维持离开时的路由
简介
PC 端路由跳转除了各种点击事件外,还经常会通过前进后退键触发,此时,为了确保导航菜单与路由地址的同步关系,就需要在菜单点击事件的基础上,新增对路由的侦听。
同时,若是希望在添加了导航持久化的情况下,在用户关闭标签(或浏览器)后重新时,可以直接重定向到离开时的路由,则需要在页面初始化时手动调用 router.push()/router.repalce() 重定
向。
思路分析
菜单与路由的同步
首先,菜单组件会接收一个 currentNav 变量的值作为当前激活的菜单项(多级菜单同理)。该变量会在以下场景中触发更新:
- 用户点击了菜单项
- 用户执行前进/后退操作,可能是点击浏览器上的按钮,有可能是触发了鼠标的物理按键
第一种场景通过事件回调处理即可;第二种情况并不需要侦听前进/后退事件,只需要侦听 route 对象就能触发,但 route 对象中并不一定包含我们需要的路径格式,因此,可以通过路由配置对象的 meta 属性添加对应的属性,比如 navPath: '/home' (这里的路径必须与菜单项的 index 属性对应,同时也是一级导航配置对象中的 path 属性的值;多级路由同理)。
同时,第二种情况可以覆盖第一种,因为点击导航也是更新路径,因此可以简化为只侦听路由变化。而在执行判定时,为了提升性能,可以为每一级路由地址添加一个对应的 oldPath 变量,仅当路由地址改变时才触发对应层级路由和相应视图组件的更新。
路由的持久化
添加合适的插件或自行开发持久化功能模块,自动保存路由状态到本地。在刷新或关闭后重新时,检测本地是否有路由记录,并将路由替换/重定向到对应的路由,以便恢复之前的浏览位置(关闭浏览器后重新时没有更早的浏览路径,若仅是关闭标签或刷新,则浏览器会自动恢复浏览路径)。
简单示例
以下以 vue3 框架为例,仅展示核心思路,不包含完整代码。
// 重进后,检测本地路径记录并恢复
onMounted(
// 这里的二级路径包含了一级路径字符串,因此直接推入二级路径即可
() => currentAsideNav.value && router.push({ path: currentAsideNav.value })
);
// 一级菜单初始化
const initTopMenu = () => {
if (!currentNav.value) updateCurrentNav(menuConfigList.value[0].index); // 首次进入软件时,激活第一项
};
// 多级菜单初始化过程 略
const initSubmenu = () => { // ... }
// 所有菜单初始化
const initMenu = () => {
// 首次加载;初始化所有菜单并激活第一项
if (!currentNav.value) {
initTopMenu();
initSubmenu();
updateCurrentSubmenuNav(asideMenuList.value[0].index || '');
}
// 刷新后重进;只需要初始化多级菜单;由于多级菜单的配置列表是由一级菜单过滤得到的,因此不能省略这一步调用
initSubmenu();
};
initMenu();
// 每次路由更新后,记录当前路径,并更新视图组件
const currentModulePath = ref('');
const currentSubModulePath = ref('');
watch(route, (newRoute) => {
const { modulePath, subModulePath } = newRoute.meta;
if (modulePath !== currentModulePath.value) {
updateCurrentNav(modulePath);
initSubmenu();
}
subModulePath !== currentSubModulePath.value &&
updateCurrentSubmenuNav(subModulePath);
});
若是不需要恢复到之前的浏览状态,则最好在每次的初始化阶段都重置菜单项的激活状态,或者在关闭标签时重置持久化数据,否则会产生“菜单已激活,但视图没有显示对应路径下页面”的问题。