当前位置: 首页 > news >正文

应用el-tabs模拟nav menu组件

目前在做的项目遇到如图所示需求。 本是个简单的menu, 但是我偏选了el-tabs组件为基础进行改写,花了好多时间,也踩了不少坑。但总算是完成啦!特此记录填坑记录。

需求

  1. 根据router表生成导航内容,实现相关效果,包括:
    • 主目录点击背景变色
    • 子目录点击变颜色
  2. url输入相关路由,导航也实现1中效果;

技术栈

  1. vue
  2. element
  3. vuex
  4. node (path模块)
  5. router全局导航守卫
  6. 项目架构:vue-element-template

实现

根据router生成menu

routerMap结构为简单的二维数组,根据需求,最多二维,不考虑更深的嵌套及外链情况;

路由详情请参考路由配置项及示例。

注册组件Navbar

这就不说了。。

应用router数据生成el-tabs

获取router数据

computed: {
    routes() {
      return this.$router.options.routes
    }
}
复制代码

渲染el-tabs,将非隐藏的router展示出来

<el-tabs v-model="activeName" @tab-click="handleClick">
  <el-tab-pane
      v-for="route in routes"
      class="slideInUp"
      v-if="!route.hidden&&route.children"
      :name="route.path"
      :label= "route.name"
      >
  </el-tab-pane>
</el-tabs>
复制代码

说到这还没什么难得,接下来问题来了。

问题一:动态渲染labelicon+text

label作为el-tab-pane的属性接收的是字符串,但是我要的label,不仅要文字,还要在上面加上我的icon. 折腾许久无果后无奈只好给element报了个feature。终于在此找到了思路: label slot.

<div slot="label">
    <svg-icon class="icons" :icon-class="iconClassName(route)" />
    <span class="nav-title">{{route.name}}</span>
  </div>
复制代码

el-tab-pane中间填上slot,我的icon们果然乖乖出现了! 开森!

sub-menu生成

因为用的el-tabnavbar,submenu生成将router.children放到el-tab-pane之间即可

问题二:动态渲染active class

根据需求,点击submenu后颜色就要发生变化,正好应用一下动态绑定class:

<li
    v-for="(item, key, index) in route.children"
    :key="item.name"
    :id = "index"
    style="cursor: pointer;"
    :class="{'sub-active':activeIndex == item.path}"
    @click="activeIndex = item.path, clickLink(item, $event)">
    {{item.name}}
</li>
复制代码

根据path的唯一性,点击时activeIndex更改为当前的path,当前submenu会添加上activeIndex类.

问题三:点击submenu路由更改

导航的重要作用就是控制路有更改,应用path.resolve可以生成当前点击的路径。li中添加的clickLink方法为:

const path = this.resolvePath(routePath)
this.$router.push(path)
复制代码

resolvePath为:

resolvePath(routePath) {
  return path.resolve(this.basePath, routePath)
}
复制代码

因为this.$router.push可以实现路由跳转,但是当前的跳转路径只解析出了子目录;

更正方案: 在el-tab-pane添加:index="resolvePath(route.path)",在最初渲染时获取相应的父级path。 之后二级路由就变成了: http://localhost:9528/#/task/index,嗯,是哀家想要的样子~

基本的功能以为就这样实现了,知道我手动输入了一下路径,,,

根据输入的path更新tab中对应项

active tab由数据activeName控制; 子菜单activeIndex项绑定的是各自的path.

失败尝试一:

添加watch,监控router变化更改activeName以及activeIndex,未果;

失败尝试二:

应用mixins生成局部钩子函数,覆盖activeName以及activeIndex,未果;

失败原因: 应用路由钩子的思路是对的,但必须全局守卫,然后发现路由变化时更新activeName以及activeIndex对应的值,这时候再用store获取新值进行覆盖。

问题四:手动输入的路径渲染menu

  • store中添加menu
const menu = {
  state: {
    menumain: '/',
    menusub:'overview'
  },
  mutations: {
    updatemain (state,n) {
      state.menumain = n
    },
    updatesub (state,n) {
      state.menusub = n
    }
  }
}
export default menu
复制代码

添加守卫函数:

router.beforeEach((to, from, next) => {
  // add menu change data
  let paths = to.path.trim().split('/')
  let activeName =''
  let activeIndex =''
  activeName = !!paths[2]==true ? '/'+ paths[1] : '/'
  store.commit('updatemain', activeName)
  activeIndex = !!paths[2]==true ? paths[2] : paths[1]
  store.commit('updatesub', activeIndex)
  //end menu
})
复制代码

navbar中更新数据:

  computed: {
    newActiveName() {
      return this.$store.getters.menumain;
    },
    newActiveSubMenu() {
      return this.$store.getters.menusub;
    }
  },
  watch: {
    newActiveName(val){
    	this.activeName = val
    },
    newActiveSubMenu(val) {
      this.activeIndex = val
    }
  }
复制代码

通过计算属性发现path更改并获取新值,然后watch监测到数据变化将新值赋给activeName以及activeIndex

看下结果吧!

多说一句:burp是一款非常牛逼的安全产品,有需要的公司可以联系我洽谈试用。 目前,安全元素正在 招聘前端工程师,有意向的也可直接加我微信咨询。

忙到半夜总算实现了,开始以为很难,做的很慢,每次搞定一个小点又觉得很容易。还是“难者不会,会者不难”吧。

另:vue中很多设计都会有意想不到的用处,比如这次用到的插槽,动态绑定class;回想当年勇jq遍历li删掉active再给某一项添加active class的日子还历历在目。数据驱动解放dom操作,yeah~

Reference:

vue 具名插槽
vue-element-admin
导航守卫
element el-tabs

本文权当组件书写笔记,多谢各位指教~

未解决的问题

  1. nested路由情况:可以在路由钩子函数里做递归处理
  2. 设备检查及手机端适配
  3. vue相关源码深入

bug修复

  1. basepath在点击tab时生成,导致如果动态跳转到该path下, basepath为空,再点击tab下子目录只有子路由,会跳转到404;

    fix: 将basepath生成在click item时同步生成

      clickLink(item, e, route) {
    	let childPath = item.path
        if (!this.isExternalLink(childPath)) {
            e.preventDefault()
            let parentPath = this.resolvePath(route.path)
            const finalPath = path.resolve(parentPath, childPath)
            this.$router.push(finalPath)
        }
    }
    复制代码

Aboutme

Author: Yanni Jia
Nickname: 非常兔
Wechat: yanni_it
Email: 385067638@qq.com

相关文章:

  • “ an error occurred during ssl communication”--VisualSVN
  • mybatis 动态SQL .1
  • 从零开始编写自己的C#框架(2)——开发前准备工作
  • 下列关于异常处理的描述中,错误的是()。
  • centos搭建svn 服务器 并同步到web 目录(总结)
  • windows phone 7 中怎样定义和使用资源(Resource)
  • Scrum丰田之道
  • 一步步学习微软InfoPath2010和SP2010--第十四章节--高级选项(9)--高级函数
  • vue+webpack 在引入图片以及在img引用变量名的本地图片报错
  • android选择图片或拍照图片上传到服务器(包括上传参数) (转)
  • 你应该了解的大数据10个新趋势
  • js编写倒计时-距离开始时间距离结束时间-结束
  • in, out, ref
  • 以太坊 ERC223 标准与 ERC20 的区别是什么?
  • 7、请求参数接收
  • php的引用
  • 2017-09-12 前端日报
  • Angular数据绑定机制
  • es6要点
  • GitUp, 你不可错过的秀外慧中的git工具
  • iOS帅气加载动画、通知视图、红包助手、引导页、导航栏、朋友圈、小游戏等效果源码...
  • java8-模拟hadoop
  • Javascript基础之Array数组API
  • Java-详解HashMap
  • Material Design
  • Protobuf3语言指南
  • Python 基础起步 (十) 什么叫函数?
  • rabbitmq延迟消息示例
  • Spring Cloud(3) - 服务治理: Spring Cloud Eureka
  • tweak 支持第三方库
  • Vue 2.3、2.4 知识点小结
  • webpack4 一点通
  • 百度贴吧爬虫node+vue baidu_tieba_crawler
  • 创建一种深思熟虑的文化
  • 反思总结然后整装待发
  • 利用DataURL技术在网页上显示图片
  • 使用agvtool更改app version/build
  • # Pytorch 中可以直接调用的Loss Functions总结:
  • #{}和${}的区别?
  • (04)Hive的相关概念——order by 、sort by、distribute by 、cluster by
  • (4)事件处理——(6)给.ready()回调函数传递一个参数(Passing an argument to the .ready() callback)...
  • (转)linux自定义开机启动服务和chkconfig使用方法
  • (转)甲方乙方——赵民谈找工作
  • (轉貼) 資訊相關科系畢業的學生,未來會是什麼樣子?(Misc)
  • ..回顾17,展望18
  • .net wcf memory gates checking failed
  • .net 逐行读取大文本文件_如何使用 Java 灵活读取 Excel 内容 ?
  • .NET/C# 编译期能确定的字符串会在字符串暂存池中不会被 GC 垃圾回收掉
  • .NetCore Flurl.Http 升级到4.0后 https 无法建立SSL连接
  • .net访问oracle数据库性能问题
  • .php文件都打不开,打不开php文件怎么办
  • @Autowired 与@Resource的区别
  • @RequestMapping处理请求异常
  • @Tag和@Operation标签失效问题。SpringDoc 2.2.0(OpenApi 3)和Spring Boot 3.1.1集成
  • [ 渗透测试面试篇 ] 渗透测试面试题大集合(详解)(十)RCE (远程代码/命令执行漏洞)相关面试题