简述

这篇文章是我项目中,遇到的一个issue,我将解决过程和方法记录下来。

本篇文章基于Vue.js进行的前端页面构建,由于仅涉及前端,将不做数据来源及其他部分的叙述。使用的CSS框架是 BootstrapVue 和 Element-UI 。数据使用 json 文件进行模拟,数据可在文章末的链接源码中查看

需求描述

项目需求是实现双导航栏:顶部导航栏和侧边导航栏。顶部导航栏用于展示一级菜单,根据点击的不同一级菜单,在屏幕左侧展示不同的二级三级导航栏。要求当前页面导航栏菜单需要高亮。

需求分析

数据,json 文件使用axios进行获取,然后赋值给Home.vue下的menus变量,再分发到Nav.vue中,进行一级导航的展示。默认情况下,高亮第一个一级菜单。如果该一级菜单下没有二级菜单和三级菜单,则不显示左侧导航栏,如果有,则展示。当点击了一级菜单时,默认页面展示该菜单下的第一个菜单的页面。

例如:点击了第一个菜单,这个菜单有二级,三级菜单,则展示该菜单下的三级菜单的页面,如果没有三级菜单,则展示二级菜单的页面,如果没有二级菜单,则展示一级菜单的页面。

默认情况下,渲染完成侧边导航栏后高亮导航栏的第一个最下级菜单

主要代码结构

遇到的问题

1、父组件与子组件相互传值

父组件传值给子组件(Home.vue,父):

父组件传值个子组件(myNav.vue,子)

子组件通过props进行数据的接收,该属性是一个数组的形式,父组件通过绑定的形式直接给组件的属性赋值便可实现父组件向子组件传值。

子组件传值给父组件(myNav.vue 子):



子组件传值给父组件(Home.vue 父):



父组件传值给子组件与子组件传值给父组件不同,父组件需要对自定义事件进行监听,而子组件需要触发该事件才能够通过$emit进行传值,在父组件中,传值的接收变量名固定为$event,不能使用其他名字进行获取数据。

2、顶部导航栏的高亮问题

因为顶部导航栏使用的是Bootstrap-Vue框架,所以高亮菜单时只需加上class:active便可以使其高亮,问题是根据需求,高亮的控制权交由父组件Home.vue,而不在子组件myNav.vue中完成,这也就涉及到了刚刚说的组件传值的问题,上述已经叙述过组件传值的问题,此处仅简述其逻辑。

子组件中绑定点击事件后,会将点击的一级菜单的ID值传给父组件。由于原需求中,可能会涉及到URL跳转到任意页面,所以,根据this.$route.path来判断是哪一个页面,再将这个页面的ID值传回给子组件。

传回后使用三元运算符,来比对是否与渲染时id匹配,若匹配,则高亮

3、左侧导航的高亮问题

需求重述:

点击一级菜单,若该菜单数据中存在二级菜单,则在左侧导航栏中显示,如不存在,则隐藏左侧导航栏。默认情况下,若该一级菜单有下属三级子菜单,则跳转第一个下属二级子菜单下的第一个下属三级菜单;若没有三级菜单,则跳转第一个下属二级子菜单的URL;若没有下属二级子菜单,则跳转至一级的URL。在此基础上,高亮当前的菜单。

与顶部导航栏不同,顶部导航栏的高亮是依靠菜单的点击和路由来控制,而侧边导航栏使用的是element-UI的导航栏,根据default-active进行高亮。

default-active的原理是该属性的值与菜单中的index进行比较,若相等则高亮。原理很简单,但是实现起来却没有那么容易。

第一次解决方案:在点击一级菜单时,上述已经说过,将id值传给父组件Home.vue中。父组件监听到该事件触发后,遍历之前通过axios获取到的数据,最终找到匹配的一级菜单,进而判断该菜单下是否有二级乃至三级菜单,若有,则显示第一个,并且将该属性的url值赋值给上述的default-active。

从原理的角度来说,该思想没有问题。可是该方法会导致一个问题,在进入页面后,点击任何一级菜单都能够正常生效,但是互相点击时,左侧导航不显示高亮,页面能够正常跳转。

例如:进入到该页面后,第一次点击任何一级菜单都没有问题,正常显示。在第二次点击任何菜单时均没有高亮显示。

在模拟数据中,有一个一级菜单没有下属菜单,若第一次点击除此菜单以外的菜单时,均可正常显示。第二次若点击除此菜单以外的菜单时,并不会高亮。

我想说的是,若第二次点击的是这个没有下属菜单的一级菜单,第三次再去点任意菜单,又可以正常显示了。

对于这个问题,至少在我看来觉得是很神奇的。于是我将这个操作模拟到每一次的页面点击中,也就是任何一次点击都做一次向那个没有数据的菜单来一次跳转,再跳转回来,发现问题解决了。

那么问题出现在哪里,应该怎样解决,总不至于,每次跳转都需要经过那个没有下属菜单的页面吧,数据是动态的,并不清楚哪个一级菜单没有下属页面菜单。

分析

跳转至无下属菜单的一级菜单时,做了两件事,1:将侧边导航栏数据清空,2:隐藏侧边导航栏。

跳转至其他菜单时,也做了两件事,1:重新赋值侧边导航栏,2:显示侧边导航栏。

首先排除隐藏/显示导航栏,样式的修改,应该不至于会出现这种问题。(其实我也偷偷试过。。)

接下来就只剩下赋值和清空数据了

该代码如下

click1thMenu (id) {
this.menus2th = []
this.active1thMenu = id
for (let i = 0; i < this.menus.length; i++) {
if (this.menus[i].id === id) {
if (this.menus[i].child !== undefined) {
this.asideWidth = '200px'
this.menus2th = this.menus[i].child
} else {
this.asideWidth = '0'
}
}
}
}

我的代码逻辑中,不管是赋值还是情况操作都会将数据清空。到这里,问题就扑朔迷离了。

好了,不卖关子了,直接说结果

我思考,会不会因为在有下属菜单的情况下,清空语句执行后再执行赋值语句,会导致情况语句成为无用代码,被浏览器直接优化掉了,于是我在赋值语句上加了一个延时函数,给他一定的延时。

methods: {
click1thMenu (id) {
this.menus2th = []
this.active1thMenu = id
for (let i = 0; i < this.menus.length; i++) {
if (this.menus[i].id === id) {
if (this.menus[i].child !== undefined) {
this.asideWidth = '200px'
setTimeout(() => {
this.menus2th = this.menus[i].child
}, 10)
} else {
this.asideWidth = '0'
}
}
}
}

然后发现问题就解决了,如果有明白这个原理的大神,也欢迎在下面留言讨论

源码地址:https://gitee.com/handsky/vue-nav

记一次Vue跨导航栏问题解决方案的更多相关文章

  1. 超详细Vue实现导航栏绑定内容锚点+滚动动画+vue-router(hash模式可用)

    超详细Vue实现导航栏绑定内容锚点+滚动动画+vue-router(hash模式可用) 转载自:https://www.jianshu.com/p/2ad8c8b5bf75 亲测有效~ <tem ...

  2. 使用vue给导航栏添加链接

    如下面的导航栏,使用vue技术给该导航栏增加链接: js代码为: navigation:function(){ new Vue({ el: '#navUl', data: { menuData:{ ' ...

  3. Nuxt/Vue自定义导航栏Topbar+标签栏Tabbar组件

    基于Vue.js实现自定义Topbar+Tabbar组件|仿咸鱼底部凸起导航 最近一直在倒腾Nuxt项目,由于Nuxt.js是基于Vue.js的服务端渲染框架,只要是会vue,基本能很快上手了. 一般 ...

  4. Vue设置导航栏为公共模块并在登录页不显示

    1.公共模块的内容可以放在App.vue中但是通常登录页面是不需要导航的,那么就需要规避登录页这时,就可以采用keep-alive结合$route.meta来实现这个功能.keep-alive 是 V ...

  5. vue 侧边导航栏递归显示

    import axios from "axios"; import tabs1 from "../tab_content/tab1.vue"; import m ...

  6. vue组件导航栏动态添加class

  7. 用Vue来实现音乐播放器(五):路由配置+顶部导航栏组件开发

    路由配置 在router文件夹下的index.js中配置路由 import Vue from 'vue' import Router from 'vue-router'//配置路由前先引入组件impo ...

  8. ElementUI+命名视图实现复杂顶部和左侧导航栏

    在了解了命名视图的用途后,发现用命名视图来实现复杂导航更加省力.更多知识请参考这里 这里只说明重要配置内容,其他内容配置请参考上一篇初始版本: ElementUI 复杂顶部和左侧导航栏实现 或参考文末 ...

  9. 使用vue封装一个tab栏切换的左侧导航栏的公共组件

     首先看最终效果图: 1.compent文件夹里添加tab文件夹,里面创建index.vue index.js index.css index.vue内的template部份代码如下:(最新更正:代码 ...

随机推荐

  1. 一篇文章带你搞懂 etcd 3.5 的核心特性

    作者 唐聪,腾讯云资深工程师,极客时间专栏<etcd实战课>作者,etcd活跃贡献者,主要负责腾讯云大规模k8s/etcd平台.有状态服务容器化.在离线混部等产品研发设计工作. etcd ...

  2. 32.qt quick-模仿QQ登录界面实现3D旋转(Rotation、Flipable)

    要想模仿QQ登录界面的3D旋转,我们需要学习Rotation和Flipable.由于没找到QQ的资源图,所以我们以两个图片为例模仿QQ的3D旋转,如下图所示: 最终效果如下所示: 1.Rotation ...

  3. 安装ogg软件报错:[INS-75012]Sofware Location specified is already an existing Oracle

    1.安装ogg软件时报错: [INS-75012]Sofware Location specified is already an existing Oracle 2.根据报错,是说我们选择ogg软件 ...

  4. Windows 11,一个新功能,一场新屠杀

    6月24日,微软正式公布了新一代操作系统:Windows 11.这次的更新距离上一代操作系统Windows 10的发布,隔了有6年之久. 在新一代的操作系统中,包含了这些亮点: 采用了全新的UI设计. ...

  5. vs中打开ashx文件没有提示,没有高亮标记解决方法

    在VS菜单中 工具 --- 选项 --- 文本编辑器 --- 文件扩展名,在右侧添加 ashx ,选中Microsoft Visual C# 保存后,再打开就行了 ashx文件头部报错后,删除 < ...

  6. K8s 部署 Prometheus + Grafana

    一.简介 1. Prometheus 一款开源的监控&报警&时间序列数据库的组合,起始是由 SoundCloud 公司开发的 基本原理是通过 HTTP 协议周期性抓取被监控组件的状态, ...

  7. 服务器通信REST、gRPC,Swagger/OpenAPI,Consul

    服务间的通信方式是在采用微服务架构时需要做出一个最基本的决策.默认的选项是通过 HTTP 发送 JSON,也就是所谓的 REST API.我们也是从 REST 开始的,但最近我们决定改用 gRPC. ...

  8. ORA-12560: 解决TNS:协议适配器错误

    1)安装成功,但无法连接数据库 2)网上查找原因:32位的不能运行64位的oracle,而且不会有64位的版本 3)解决办法:大致是修改客户端数据库为32位的(此方法OK) (1)解压instantc ...

  9. css 背景图片铺满

    body { width: 100%; height: 100%; background: url(img/loginbg.png); background-size: 100% 100%; back ...

  10. frp+nginx内网穿透

    frp+nginx内网穿透 背景:自己有台内网Linux主机,希望被外网访问(ssh.http.https): 准备工作 内网Linux主机-c,可以访问c主机和外网的主机-s(windows/lin ...