Vue设计tabs和菜单联动
总的原则
监听路由的变化实现 menu 与 tabs 的双向绑定。
menu 的实现
- menu 只需要点击能够实现跳转路由即可,这里跳转的方式,使用 click 还是直接用 el-menu 组件自身的 route 模式,取决于路由跳转是使用命名路由还是 path 直接跳,方便的程度与否取决于生成的菜单的结构。
- 该系统的实现基于点击菜单事件实现路由跳转,跳转的方式是命名路由跳转。
tabs 的引入的三个方案
三个方案的不同点只在于点击菜单,如何生成 tab 的改进,tab 上的切换实现都是相同的。
tab 的存储原则
tabs 的所有数据存储在 tabStore 里,主要就是 tabs tabsActive menuActive acheComponents(keep-alive 缓存的组件 name)
方案一
- 原则:点击菜单项将 tab 需要的信息构造成新的 tab 或者在原 tab 里进行切换。
- 实现:
- 点击菜单将菜单项对应的 title 和 path(实际是命名路由)构造新的 tab 给 tabStore.tabs 里,并进行路由跳转。
- 表现形式上体现切换到指定的 tab,就将 tabActive 转为新的路由组件对应的名字上即可
1
2
3
4
5
6
7
8
9
10const sendMessageToTabs = (menuOption: tabType, event: any) => {
menuActive.value = event.index;
tabOption.title = menuOption.title;
tabOption.path = menuOption.path;
console.log("tabOption", tabOption);
tabsStore.addTab(menuOption);
router.push({
name: menuOption.path,
});
};
- 缺点:将 menu 组件和 tabs 组件高度绑定了,点击 menu 需要传递给 tabs 组件相应信息。
方案二
- 原则:tab 下存储的组件表现形式实际只是不同路由切换的结果,因此可以考虑分离 tab 和 menu 的耦合关系,点击 menu 只进行路由跳转,可以在 layout 组件下只监听路由变化即可,路由变化来考虑是否新增 tab。
- 实现
- layout 组件下监听 route,route 发生变化,route.name 和 route.meta.name 存储有构造 tab 的信息
- 缺点:
- layout 组件监听 route 实现了菜单情况下 spa 页面的 tab 增加,但是在退出登录时会也监听到了 login 这个路由也会新增到 tabs 内部,下次登录的时候就会出现登录这个选项卡就会出现在 tab 栏里。
1
2
3watch(route, (newRoute) => {
tabsStore.handleTab(newRoute);
});
- layout 组件监听 route 实现了菜单情况下 spa 页面的 tab 增加,但是在退出登录时会也监听到了 login 这个路由也会新增到 tabs 内部,下次登录的时候就会出现登录这个选项卡就会出现在 tab 栏里。
方案三
- 原则: 选择将路由变化放在路由拦截器里处理.
- 实现:路由拦截分为了以下几种情况,只需要在后两种情况下操纵 tab 即可,特殊情况如刷新,404 页面,route 都会匹配两次,也会操作 tab,这两种情况下第一次匹配都会出现 route.name 都是 undefined,再单独给 404 路由不设置 name,就可以实现只有 spa 与 tab 相关。
- 去登录页面
- 第一次来到首页(刷新页面)
- 正常的切换到不同的页面
1 |
|
tabs 的实现
原则:真正菜单对应的路由组件并没有放在 el-tab-panel 下,watch 在通用布局组件 layout 下面监听 route,route 发生变化,说明 tab 会出现相应的变化操作。不同 tab 的页面应该处于缓存状态,所以应该用 keep-alive 缓存状态,但是在关闭 tab 的时候相应的也需要对不用的组件进行销毁,这里不采取 destroy 来销毁组件,采用对 router-view 使用 include 来选择包含的组件进行缓存,关闭 tab 就移出。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// layout.vue 在这个页面监听路由的变化
<el-main class="main">
<div class="nav-tabs">
<nav-tabs></nav-tabs>
</div>
<router-view v-slot="{ Component }" >
<transition>
<keep-alive :include="cacheComponents" :max="10">
<component :is="Component" />
</keep-alive>
</transition>
</router-view>
</el-main>
const route = useRoute();
const tabsStore = useTabStore();
const { cacheComponents } = storeToRefs(tabsStore);操作 Tab:Tab 的数据全部存储在 store/tabStore 下
- handleTab: 将路由拦截的路由对象 to 传递过来判断即可,判断是否是新增还是跳转即可。
删除 tab
- 删除后,选中的路由应该是上一个 tab 对应的路由路径
- 删除最后一个自动对应首页对应的路由
点击 tab 实现路由的切换管理:直接点击的时候实现路由跳转即可,修改菜单的选中状态即可实现。
**这里还存在问题:路由组件存放在 el-tab-pannel 下会出现下面情况,有几个 tab 页面,选中其中一个 tab 页,它对应的组件 setup 会执行几次;具体来说有三个 tab 页 a,b,c,点击 a,a 页面的 setup 会执行三次,具体情况未知待测**。
Vue设计tabs和菜单联动
https://sunburst89757.github.io/2022/05/29/vue-tabs-design/