前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我攻克的技术难题 - BuildAdmin07:导航栏动态添加tabs如何实现

我攻克的技术难题 - BuildAdmin07:导航栏动态添加tabs如何实现

原创
作者头像
叫我阿柒啊
修改2024-01-24 00:25:33
2840
修改2024-01-24 00:25:33
举报

前言

之前的几篇文章都是基于comtainer布局的aside边栏部分来写的,像logo、menu以及Icon图标组件,后面也写了关于路由动态加载和菜单渲染的文章。

今天就撤离aside,来讲一下header部分的实现。

NavBar导航栏

在BuidAdmin中,header部分实现了NavBar。可以看到NavBar由两部分构成,一个是左侧的可变的tab页,一个是右边固定的菜单栏。

通过源码,来看看BuildAdmin的header是如何实现的。

可以看到header的内容是由 \<component> 动态组件实现的,使用is属性绑定不同的导航栏组件。通过修改pinia定义的状态变量 config.layout.layoutMode,然后拼接NavBar,来映射defineComponent中的导航组件。

pinia中定义了四种布局模式,Default|Classic|Streamline|Double,默认是Default。不同的布局也定义了不同的NavBar。这里看一下效果。

一开始BuildAdmin使用的就是默认布局。我在这里不需要使用动态组件,也不需要实现其他三个布局组件,我只实现一个默认布局的navBar。我们在navBar目录下查看默认布局中navBar是如何定义的。

从default.vue也可以看到,NavBar是由NavTabs和NavMenus两个组件组成的 这里就先看tabs的实现。

NavTab

用开发者工具查看源码,分析tab的实现。

从源码可以看到: 整个导航栏就是一个div,里面有多个tab。一个tab是由一个div和一个Icon元素组成。

最简单的代码实现:

这时候还没有定义css,展示出来的效果如下:

接着定义css样式。

主要使用的是flex弹性布局,然后水平分布居中。BuildAdmin中是在navBar中通过deep透传样式给子元素tab的。我这里直接抽离这部分代码直接到tab.vue中,这样便于直观阅读,我们看一下添加css后的样式。

同时,选中tab时字体颜色加深;选中关闭按钮时候,按钮会有动画。

当然,上面的tab是写死的,点击菜单栏并不能增加,点击关闭按钮也无法关闭。所以接下来就是实现两个部分:添加按钮和关闭按钮。

动态添加tab

我们点击menu菜单,如果没有这个tab就新建一个,如果有这个页面tab,就跳转,可以看到,tab的创建、跳转是和路由同步的,所以tab的实现离不开router。

在BuildAdmin中的tabs.vue中实现了动态添加tab的功能。

使用了路由守卫onBeforeRouteUpdate来监测路由是否更新,如果更新则触发 addTabs() 添加tab到tabsNav的tabsView中去。

实现动态添加tab

但是onBeforeRouteUpdate使用起来有一定的难度,搞了好久,查阅了好多文章都没有达到想要的效果,所以这一块我就换了一种思路,就用了watch来监控activeRoute。

使用watch的话就需要自己去另外实现一些功能,比如activeRoute是如何设置的。那么,activeRoute是什么呢,接着往下看。

1. 定义tabs状态

使用pinia定义了一个userNavTabs的路由信息状态,方便各个组件修改路由的状态。

之前在路由动态加载中就提到过,在router.ts工具类中,通过 setTabsViewRoutes()将处理好的菜单路由放到了tabsViewRoutes中,然后渲染menu。

activeRoute、activeIndex、tabsView 是实现tabs的三个变量。activeRoute表示当前激活的路由是哪个,这样才能利用route.push 跳转到目标页面。

tabsView是存放tabs的地方,一共两个作用:1是这样在NavTabs组件中渲染一个tab,2是用于排除重复tab的作用。

最后就是activeIndex,表示当前激活的路由在tabsView中的下标。

2. 获取activeRoute

使用onBeforeRouteUpdate的好处就是,这个导航守卫函数,有to和from的路由参数。使用watch只能监控某一个路由的变化,没法获取to和from两个路由,只能从其他导航守卫来处理这两个路由。

activeRoute为激活的路由,什么是激活的路由?那肯定是即将要跳转到目标路由,在router导航守卫afterEach中,可以获取到to路由

代码语言:JavaScript
复制
router.afterEach((to, from) => {
    // 用于添加tab
    const navTabs = useNavTabs()
    // 将即将跳转的路由设置为activeRoute
    navTabs.setActiveRoute(to)
}

我们在这里调用navTabs.setActiveRoute(to) 将目标路由设置为activeRoute。稍等会儿我们看看setActiveRoute方法的定义。

3. watch回调函数

watch是监控一个变量的变化,然后执行一个回调函数,在tab的新增、关闭、跳转中,变化的还是路由,activeRoute作为一个一直在变化的目标路由,且是一个共享状态变量,所以用来作为watch的变量再也合适不过了。

代码语言:javascript
复制
watch(() => navTabs.state.activeRoute,
  () => {
      navTabs.addTabs()
      nextTick(() => {
          const div = tabsRefs.value[navTabs.state.activeIndex]
          selectNavTab(div)
      })
})

当点击菜单,activeRoute会发生变化,触发watch调用回调函数,回调函数就会调用状态变量的addTabs() 函数。我们来看看addTabs的定义:

主要核心代码逻辑就是:遍历tabsView,根据路由的path判断activeRoute是否在tabsView中,如果在,则结束方法;如果不在,将activeRoute放到tabsView中。在这里,就保证了在tabsView中的tab不会重复。

4. setActiveRoute

这里也一起把setActiveRoute 看了,当在路由导航守卫afterEach调用此方法时,就会将afterEach传过来的to路由赋值给activeRoute,然后还是遍历tabsView,匹配判断to在tabsView的下标位置,然后赋值给activeIndex,activeIndex有什么用,后面在在tab关闭会讲。

看完setActiveRoute有两个疑惑:

为什么要判断path为admin?因为在整个项目中会有很多路由,例如上面讲到的404、loading都是,所以这里的路由必须保证为menu中的路由,所以要以admin开头。

为什么要调用addTabs方法?因为只有addTabs方法中才会向tabsView添加路由,不执行在tabsView中就找不到activeRoute的index,activeIndex也无法赋值。

总结:只要路由跳转,activeRoute和activeIndex就会改变。

4. 创建tab

最后就是实现tabs.vue,遍历tabsView渲染导航栏的tabs。

结语

这样就实现了tab的基本功能,后面会接着写tab的关闭和切换。

我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • NavBar导航栏
  • NavTab
  • 动态添加tab
  • 实现动态添加tab
    • 1. 定义tabs状态
      • 2. 获取activeRoute
        • 3. watch回调函数
          • 4. setActiveRoute
            • 4. 创建tab
            • 结语
            相关产品与服务
            云开发 CLI 工具
            云开发 CLI 工具(Cloudbase CLI Devtools,CCLID)是云开发官方指定的 CLI 工具,可以帮助开发者快速构建 Serverless 应用。CLI 工具提供能力包括文件储存的管理、云函数的部署、模板项目的创建、HTTP Service、静态网站托管等,您可以专注于编码,无需在平台中切换各类配置。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档