0 环境
1 参考文档
2 前言
现找到src/layouts/LayoutVertical/index.vue
里的<Main />
,点进去,找到Tabs
组件,它是我们要探索的主角,看下图:
先了解下@tab-click
和@tab-remove
,如下图:
自定义标签页的内容,如下图:
3 逻辑梳理
首先先看el-tabs
,@tab-click
和@tab-remove
,以及 <template #label> 自定义标签页,看上面的前言或者el-tabs
,这里就不多解释了。先看v-model
里tabsMenuValue,找到它在哪里定义的,它对应的是route.fullPath。如下图:
再看如下图的代码:
定位到tabsMenuList的定义的位置,如下图:
tabStore后的tabsMenuList对应的接口类型src/stores/interface/index.ts,也可以看下图:
看名字大概能猜出来。
这里tabsMenuList实现在src/stores/modules/tabs.ts里,但是你往下翻看,确实没有初始化的方法,只有tabsMenuList=[]。那在回到Tabs/index.vue
,先到onMounted
里看下,这里面的tabsDrop
,点进去看一下,作者的注释也写了拖拽排序,initTabs
看名字就有点像,点进去看一下,确实是的,代码如下图,其实就是遍历路由,若是固定的标签,以及过滤掉隐藏、不是全屏。tabsParams
属性,图标和标题是从meta
里拿icon
和title
,path和name都知道的,close
它得到的是meta.isAffix取反,之后再看。isKeepAlive
指定这个组件是否需要缓存信息,正常是保持缓存的。
tabStore.addTabs(tabsParams);,看下图代码,貌似这里也没有添加进去呀。
但是仔细观察,会发现这里还有个watch
,它在初始化tab
之前执行的。代码如下:
监听route.fullPath
,发生变化了,判断若是全屏,直接返回。route.fullPath
传给tabsMenuValue
(tabsMenuValue
默认绑定的就是route.fullPath
),看下图,el-tabs
绑定的v-model
就是它,下面的流程和初始化tab
大差不差。
watch(
() => route.fullPath,
() => {
if (route.meta.isFull) return;
tabsMenuValue.value = route.fullPath;
const tabsParams = {
icon: route.meta.icon as string,
title: route.meta.title as string,
path: route.fullPath,
name: route.name as string,
close: !route.meta.isAffix,
isKeepAlive: route.meta.isKeepAlive as boolean
};
// console.log("打印tabsParams --> ", tabsParams);
tabStore.addTabs(tabsParams);
},
{ immediate: true }
);
对于route
后端的传过来的动态路由的数据没印象的,可以看src/assets/mock/geeker/menu/list.json
,如下图:
在点击addTabs
进去,它做的内容就是tabsMenuList
判断你加入的这条path
,是否在它里面已经存在了,不存在才会push
进来,首次进来,首页就被加入数组中了。再往下是添加keepalive
,这里判断就是在keepAliveName
字符串数组里面,没有route.name
(这里的判断感觉有点不对,应该是判断path
的吧,等源码全读完了在确定), 并且route.meta.isKeepAlive
为真,再往下,选中addKeepAliveName
(它相当于addKeepAliveName(route.fullPath)
)点进去,这个names
不存在,才会push
。
4 小结
先理清
el-tabs
中tabsMenuValue
怎么来的,tabsMenuList
初始化的值是从哪里来的。